From f35a0d89a6c4b5e647c97ac4e708bb2799c74422 Mon Sep 17 00:00:00 2001
From: yomguy <>
Date: Mon, 26 Nov 2007 11:15:56 +0000
Subject: [PATCH] * Create new Course, TeleOddcast, WebView classes * Begin to
rewrite main()
---
teleoddcast.py | 522 ++++++++++++++++++++++++++-----------------------
tools.py | 69 +++++++
xmltodict.py | 41 ++++
3 files changed, 389 insertions(+), 243 deletions(-)
create mode 100644 tools.py
create mode 100644 xmltodict.py
diff --git a/teleoddcast.py b/teleoddcast.py
index 1c00bc7..42a954e 100755
--- a/teleoddcast.py
+++ b/teleoddcast.py
@@ -20,268 +20,304 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
-version = '0.2'
+version = '0.3'
+
import os
import cgi
import shutil
import datetime
import time
+from tools import *
from mutagen.oggvorbis import OggVorbis
-def get_pid(proc,uid):
- """Get a process pid filtered by arguments and uid"""
- (list1, list2) = os.popen4('pgrep -f -U '+str(uid)+' '+'"'+proc+'"')
- pids = list2.readlines()
- if pids != '':
- for pid in pids:
- index = pids.index(pid)
- pids[index] = pid[:-1]
- return pids
-
-
-def get_lines(file):
- """Get lines from a file"""
- fic = open(file,'r')
- lines = fic.readlines()
- fic.close()
- return lines
-
-def clean_string(string):
- """removes blank spaces and accents"""
- string = string.replace(' ','_')
- string = string.replace('é','e')
- string = string.replace('è','e')
- return string
-
-def start_stream(odd_conf_file, lock_file, media_dir, title, department, course, session, professor, comment):
- oddconf = open(odd_conf_file,'r')
- params = oddconf.readlines()
- oddconf.close()
- newlines = []
- for line in params:
- if 'ServerDescription' in line.split('='):
- ServerDescription = title+'_-_'+department+'_-_'+course+'_-_'+session+'_-_'+professor+'_-_'+comment
- ServerDescription = ServerDescription.replace(' ','_')
- newlines.append('ServerDescription='+ServerDescription+'\n')
- elif 'ServerName' in line.split('='):
- ServerName=title+'_-_'+department+'_-_'+course+'_-_'+session
- ServerName=clean_string(ServerName)
- newlines.append('ServerName='+ServerName+'\n')
- elif 'ServerMountpoint' in line.split('='):
- mount_point = '/'+clean_string(title)+'_-_'+clean_string(department)+'_-_'+clean_string(course)+'.ogg'
- newlines.append('ServerMountpoint='+mount_point+'\n')
- else:
- newlines.append(line)
- oddconf = open(odd_conf_file,'w')
- oddconf.writelines(newlines)
- oddconf.close()
- os.system('oddcastv3 -n "'+clean_string(course)+'" -c '+odd_conf_file+ \
- ' alsa_pcm:capture_1 alsa_pcm:capture_2 > /dev/null &')
- lock = open(lock_file,'w')
- lock_text = clean_string(title+'_*_'+department+'_*_'+course+'_*_'+session+'_*_'+professor+'_*_'+comment)
- lock_text = lock_text.replace('\n','')
- lock.write(lock_text)
- lock.close()
- time.sleep(1)
- return mount_point
-
-def start_rip(url, mount_point, media_dir, department):
- output_dir = media_dir+os.sep+department+os.sep
- #print mount_point
- if not os.path.exists(output_dir):
- os.mkdir(output_dir)
- os.system('streamripper '+url+mount_point+' -d '+output_dir+' -D "%S" -s -t --quiet > /dev/null &')
-
-def stop_oddcast(pid):
- os.system('kill -9 '+pid)
-
-def rm_lockfile(lock_file):
- os.system('rm '+lock_file)
-
-def stop_rip(pid,media_dir,title,department,course,session,professor,comment):
- os.system('kill -9 '+pid)
- time.sleep(1)
- date = datetime.datetime.now().strftime("%Y")
- filename = clean_string(title+'_-_'+department+'_-_'+course+'_-_'+session+'_-_'+date+'_-_'+professor+'_-_'+comment+'.ogg')
- dirname = media_dir + os.sep + department + os.sep + clean_string(title+'_-_'+department+'_-_'+course+'_-_'+session)
- if os.path.exists(dirname) and os.path.exists(dirname+os.sep+'incomplete'):
- shutil.move(dirname+os.sep+'incomplete'+os.sep+' - .ogg',dirname+os.sep)
- shutil.rmtree(dirname+os.sep+'incomplete'+os.sep)
- os.rename(dirname+os.sep+' - .ogg',dirname+os.sep+filename)
-
-def get_params_from_lock(lock_file):
- lockfile = open(lock_file,'r')
- params = lockfile.readline()
- params_ok = params.split('_*_')
- lockfile.close()
- return params_ok
-
-def write_tags(media_dir,title,department,course,session,professor,comment):
- date = datetime.datetime.now().strftime("%Y")
- filename = clean_string(title+'_-_'+department+'_-_'+course+'_-_'+session+'_-_'+date+'_-_'+professor+'_-_'+comment+'.ogg')
- new_title = clean_string(title+'_-_'+department+'_-_'+course+'_-_'+session)
- dirname = media_dir + os.sep + department + os.sep + new_title
- if os.path.exists(dirname+os.sep+filename):
- audio = OggVorbis(dirname+os.sep+filename)
- audio['TITLE'] = new_title
- audio['ARTIST'] = professor
- audio['ALBUM'] = title
- audio['DATE'] = date
- audio['GENRE'] = 'Vocal'
- audio['SOURCE'] = title
- audio['ENCODER'] = 'TeleOddCast by Parisson'
- audio['COMMENT'] = comment
- audio.save()
-
-# Required header that tells the browser how to render the HTML.
-print "Content-Type: text/html\n\n"
-
-def header(title):
- print ""
- print "
"
- print "\t"+title+""
- print ""
- print ""
- print ""
- print ""
- print ""
-
-def colophon():
- print "
"
- print "TeleOddCast "+version+" ©
2007 Parisson. Tous droits réservés."
- print "
"
+
+class Course:
+ """A course in a class room"""
+
+ def __init__(self, dict):
+ self.department = course_dict['department']
+ self.course = course_dict['course']
+ self.session = course_dict['session']
+ self.professor = course_dict['professor']
+ self.comment = course_dict['comment']
+
+ def get_info(self):
+ return self.title, self.department, self.course, self.session, self.professor, self.comment
+
+
+class TeleOddCast(Course):
+ """Control the Oddcastv3-jack thread which send audio data to the icecast server
+ and the Streamripper thread which write audio on the hard disk"""
+
+ def __init__(self, conf_file, course_dict):
+ Course.__init__(self, course_dict)
+ self.conf = xml2dict(conf_file)
+ self.title = self.conf['title']
+ self.root_dir = self.conf['root_dir']
+ self.media_dir = self.conf['media_dir']
+ self.server = self.conf['server']
+ self.port = self.conf['port']
+ self.url = 'http://'+self.server+':'+self.port
+ self.uid = os.getuid()
+ self.odd_pid = get_pid('^oddcastv3 -n [^LIVE]', self.uid)
+ self.rip_pid = get_pid('streamripper ' + self.url + self.mount_point, self.uid)
+ self.odd_conf_file = self.conf['odd_conf_file']
+ self.ServerDescription = clean_string('_-_'.join(self.title,
+ self.department,
+ self.course,
+ self.session,
+ self.professor,
+ self.comment))
+ self.ServerName = clean_string('_-_'.join(self.title,
+ self.department,
+ self.course,
+ self.session))
+ self.mount_point = '/' + clean_string(self.title) + '_-_' + \
+ clean_string(self.department) + '_-_' + \
+ clean_string(self.course)+'.ogg'
+ self.lock_file = self.root_dir + self.ServerDescription + '.lock'
+ self.filename = self.ServerDescription + '.ogg'
+
+ def set_oddcast_conf(self):
+ oddconf = open(self.odd_conf_file,'r')
+ lines = oddconf.readlines()
+ oddconf.close()
+ newlines = []
+ for line in lines:
+ if 'ServerDescription' in line.split('='):
+ newlines.append('ServerDescription=' + \
+ self.ServerDescription.replace(' ','_') + '\n')
+
+ elif 'ServerName' in line.split('='):
+ newlines.append('ServerName=' + self.ServerName + '\n')
+
+ elif 'ServerMountpoint' in line.split('='):
+ newlines.append('ServerMountpoint=' + self.mount_point + '\n')
+
+ else:
+ newlines.append(line)
+
+ oddconf = open(self.odd_conf_file,'w')
+ oddconf.writelines(newlines)
+ oddconf.close()
+
+ def start_oddcast(self):
+ command = 'oddcastv3 -n "'+clean_string(self.course)+'" -c '+self.odd_conf_file+ \
+ ' alsa_pcm:capture_1 alsa_pcm:capture_2 > /dev/null &'
+ os.system(command)
+ self.set_lock()
+ time.sleep(1)
+ return mount_point
+
+ def set_lock(self):
+ lock = open(self.lock_file,'w')
+ lock_text = clean_string('_*_'.join(self.title,
+ self.department,
+ self.course,
+ self.session,
+ self.professor,
+ self.comment))
+ lock_text = lock_text.replace('\n','')
+ lock.write(lock_text)
+ lock.close()
+
+
+ def del_lock(self):
+ os.remove(self.lock_file)
+
+ def start_rip(self):
+ output_dir = self.media_dir + os.sep + self.department + os.sep
+ #print mount_point
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
+ command = 'streamripper ' + self.url + self.mount_point + \
+ ' -d '+output_dir+' -D "%S" -s -t --quiet > /dev/null &'
+ os.system(command)
+
+ def stop_oddcast(self):
+ os.system('kill -9 ' + self.odd_pid[0])
+
+ def stop_rip(self):
+ os.system('kill -9 ' + self.rip_pid[0])
+ time.sleep(1)
+ date = datetime.datetime.now().strftime("%Y")
+ dirname = self.media_dir + os.sep + self.department + os.sep + \
+ clean_string('_-_'.join(self.title, self.department, self.course, self.session))
+
+ if os.path.exists(dirname) and os.path.exists(dirname+os.sep+'incomplete'):
+ shutil.move(dirname+os.sep+'incomplete'+os.sep+' - .ogg',dirname+os.sep)
+ shutil.rmtree(dirname+os.sep+'incomplete'+os.sep)
+ os.rename(dirname+os.sep+' - .ogg',dirname+os.sep+self.filename)
+
+ def write_tags(self):
+ date = datetime.datetime.now().strftime("%Y")
+ new_title = clean_string('_-_'.join(self.title, self.department, self.course, self.session)
+ dirname = self.media_dir + os.sep + self.department + os.sep + new_title
+ if os.path.exists(dirname+os.sep+self.filename):
+ audio = OggVorbis(dirname+os.sep+self.filename)
+ audio['TITLE'] = new_title
+ audio['ARTIST'] = self.professor
+ audio['ALBUM'] = self.title
+ audio['DATE'] = date
+ audio['GENRE'] = 'Vocal'
+ audio['SOURCE'] = self.title
+ audio['ENCODER'] = 'TeleOddCast by Parisson'
+ audio['COMMENT'] = self.comment
+ audio.save()
+
+ def start(self):
+ self.set_lock()
+ self.set_oddcast_conf()
+ self.start_oddcast()
+ self.start_rip()
+
+ def stop(self):
+ self.stop_rip
+ self.write_tags()
+ self.stop_oddcast()
+ self.del_lock()
-def footer():
- print "
"
- print ""
- print ""
-
-
-
-def start_form(title, departments, courses):
- header(title)
- print ""
- print "
"
- print "\t
"
- print "\t
Attention, il est important de remplir tous les champs, y compris le commentaire !
"
- print "
"
- print ""
- print "\t"
- print "\t"
- print "\t"
- print "
"
- colophon()
- footer()
-
-
-def stop_form(url,title, department, course, session, professor, comment):
- """Stop page"""
- header(title)
- print ""
- print "\t
Cette formation est en cours de diffusion :
"
- print "
"
- print "\t
"
- print "
"
- print "
"
- print "
"
- print ""
- print "\t"
- print "\t"
- print "\t"
- print "
"
- colophon()
- footer()
+
+class WebView:
+
+ def __init__(self, school_file):
+ self.conf = xml2dict(school_file)
+ self.departments = self.conf['department']
+ self.url = self.conf['url']
+
+ def header(self):
+ # Required header that tells the browser how to render the HTML.
+ print "Content-Type: text/html\n\n"
+ print ""
+ print ""
+ print "\t"+self.title+""
+ print ""
+ print ""
+ print ""
+ print ""
+ print ""
+
+ def colophon(self):
+ print "
"
+ print "TeleOddCast "+self.version+" ©
2007 Parisson. Tous droits réservés."
+ print "
"
+
+ def footer(self):
+ print "
"
+ print ""
+ print ""
+
+ def start_form(self):
+ self.header()
+ print ""
+ print "
"
+ for department in self.departments:
+ courses = self.conf[department]['courses']
+ print "\t
"
+ print "\t
Attention, il est important de remplir tous les champs, y compris le commentaire !
"
+ print "
"
+ print ""
+ print "\t"
+ print "\t"
+ print "\t"
+ print "
"
+ self.colophon()
+ self.footer()
+
+
+ def stop_form(self, course_dict):
+ """Stop page"""
+ title = course_dict['title']
+ department = course_dict['department']
+ course = course_dict['course']
+ session = course_dict['session']
+ professor = course_dict['professor']
+ comment = course_dict['comment']
+
+ self.header()
+ print ""
+ print "\t
Cette formation est en cours de diffusion :
"
+ print "
"
+ print "\t
"
+ print "
"
+ print "
"
+ print "
"
+ print ""
+ print "\t"
+ print "\t"
+ print "\t"
+ print "
"
+ colophon()
+ footer()
def main():
"""Main function"""
- title = 'Pre-barreau - Augustins'
- root_dir = '/var/www/cgi-bin/'
- media_dir = root_dir + 'media/'
- server = 'localhost'
- port = '8000'
- url = 'http://'+server+':'+port
+
+ conf_file = 'teleoddcast.xml'
+ school_file = 'pre-barreau.xml'
+ odd_conf_file = 'teleoddcast.cfg'
+ lock_file = 'teleoddcast.lock'
uid = os.getuid()
-
- departments = get_lines(root_dir+'pre-barreau_departments.txt')
- courses = get_lines(root_dir+'pre-barreau_courses.txt')
- odd_conf_file = root_dir+'teleoddcast.cfg'
-
- oddcast_pid = get_pid('^oddcastv3 -n [^LIVE]',uid)
- lock_file = root_dir+'teleoddcast.lock'
-
+ odd_pid = get_pid('^oddcastv3 -n [^LIVE]', uid)
+
+ w = WebView(school_file)
form = cgi.FieldStorage()
-
- if oddcast_pid == [] and form.has_key("action") and \
- form.has_key("department") and form.has_key("course") and form.has_key("professor") \
- and form.has_key("comment") and form["action"].value == "start":
-
- mount_point = start_stream(odd_conf_file, lock_file, media_dir, title,
- form["department"].value, form["course"].value,
- form["session"].value, form["professor"].value,
- form["comment"].value)
-
- department = form["department"].value
- start_rip(url,mount_point,media_dir,department)
-
- stop_form(url,title,
- form["department"].value, form["course"].value,
- form["session"].value, form["professor"].value,
- form["comment"].value)
-
- elif oddcast_pid != [] and os.path.exists(lock_file) and not form.has_key("action"):
-
- title,department,course,session,professor,comment = get_params_from_lock(lock_file)
- stop_form(url,title,department,course,session,professor,comment)
+
+ if odd_pid == [] and form.has_key("action") and \
+ form.has_key("department") and form.has_key("course") and form.has_key("professor") \
+ and form.has_key("comment") and form["action"].value == "start":
+
+ course_dict = {'department': form["department"].value,
+ 'course': form["course"].value,
+ 'session': form["session"].value,
+ 'professor': form["professor"].value,
+ 'comment': form["comment"].value}
+
+ t = TeleOddCast(conf_file, course_dict)
+ t.start()
+ w.stop_form(course_dict)
+
+ elif odd_pid != [] and os.path.exists(lock_file) and not form.has_key("action"):
+ t = TeleOddCast(conf_file, course_dict)
+ title,department,course,session,professor,comment = t.get_info()
+ w.stop_form(course_dict)
elif oddcast_pid != [] and form.has_key("action") and form["action"].value == "stop":
-
+ t = TeleOddCast(conf_file, course_dict)
if os.path.exists(lock_file):
- title,department,course,session,professor,comment = get_params_from_lock(lock_file)
-
- stop_oddcast(oddcast_pid[0])
- mount_point = '/'+clean_string(title)+'_-_'+clean_string(department)+'_-_'+clean_string(course)+'.ogg'
- #print mount_point
- streamripper_pid = get_pid('streamripper '+url+mount_point,uid)
-
- if streamripper_pid != []:
- stop_rip(streamripper_pid[0],media_dir,title,department,course,session,professor,comment)
- write_tags(media_dir,title,department,course,session,professor,comment)
-
- rm_lockfile(lock_file)
-
- start_form(title, departments, courses)
+ title,department,course,session,professor,comment = t.get_info()
+ t.stop()
+ w.start_form()
elif oddcast_pid == []:
- start_form(title, departments, courses)
+ w.start_form()
# Call main function.
-main()
+if __name__ == '__main__':
+ main()
diff --git a/tools.py b/tools.py
new file mode 100644
index 0000000..425cd6a
--- /dev/null
+++ b/tools.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+# *-* coding: utf-8 *-*
+"""
+ teleoddcast
+
+ Copyright (c) 2006-2007 Guillaume Pellerin
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+import os
+import cgi
+import shutil
+import datetime
+import time
+from xmltodict import *
+from mutagen.oggvorbis import OggVorbis
+
+def get_lines(file):
+ """Get lines from a file"""
+ fic = open(file,'r')
+ lines = fic.readlines()
+ fic.close()
+ return lines
+
+def clean_string(string):
+ """removes blank spaces and accents"""
+ string = string.replace(' ','_')
+ string = string.replace('é','e')
+ string = string.replace('è','e')
+ return string
+
+def xml2dict(conf_file):
+ confile = open(conf_file,'r')
+ conf_xml = confile.read()
+ confile.close()
+ dict = xmltodict(conf_xml,'utf-8')
+ return dict
+
+def get_pid(proc,uid):
+ """Get a process pid filtered by arguments and uid"""
+ (list1, list2) = os.popen4('pgrep -f -U '+str(uid)+' '+'"'+proc+'"')
+ pids = list2.readlines()
+ if pids != '':
+ for pid in pids:
+ index = pids.index(pid)
+ pids[index] = pid[:-1]
+ return pids
+
+def get_params_from_lock(lock_file):
+ lockfile = open(lock_file,'r')
+ params = lockfile.readline()
+ params_ok = params.split('_*_')
+ lockfile.close()
+ return params_ok
+
+
diff --git a/xmltodict.py b/xmltodict.py
new file mode 100644
index 0000000..b85d556
--- /dev/null
+++ b/xmltodict.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Easily import simple XML data to Python dictionary
+# http://www.gmta.info/publications/parsing-simple-xml-structure-to-a-python-dictionary
+
+import xml.dom.minidom
+
+def haschilds(dom):
+ # Checks whether an element has any childs
+ # containing real tags opposed to just text.
+ for childnode in dom.childNodes:
+ if childnode.nodeName != "#text" and \
+ childnode.nodeName != "#cdata-section":
+ return True
+ return False
+
+def indexchilds(dom, enc):
+ childsdict = dict()
+ for childnode in dom.childNodes:
+ name = childnode.nodeName.encode(enc)
+ if name == "#text" or name == "#cdata-section":
+ # ignore whitespaces
+ continue
+ if haschilds(childnode):
+ v = indexchilds(childnode, enc)
+ else:
+ v = childnode.childNodes[0].nodeValue.encode(enc)
+ if name in childsdict:
+ if isinstance(childsdict[name], dict):
+ # there is multiple instances of this node - convert to list
+ childsdict[name] = [childsdict[name]]
+ childsdict[name].append(v)
+ else:
+ childsdict[name] = v
+ return childsdict
+
+def xmltodict(data, enc=None):
+ dom = xml.dom.minidom.parseString(data.strip())
+ return indexchilds(dom, enc)
+
+
--
2.39.5