From: yomguy <> Date: Mon, 23 Jun 2008 14:53:48 +0000 (+0000) Subject: * Change package name to telecaster X-Git-Tag: 0.9~329 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=021784a9424072d12c252be917c36d851789676c;p=telecaster-client.git * Change package name to telecaster * Detect last osscastv3 process with pgrep --- diff --git a/etc/pre-barreau_conferences.xml b/etc/pre-barreau_conferences.xml index f0b17ac..d6116dd 100644 --- a/etc/pre-barreau_conferences.xml +++ b/etc/pre-barreau_conferences.xml @@ -1,125 +1,111 @@ - - http://augustins.pre-barreau.com - Augustins - Pré-Barreau + + http://localhost + PRE-BARREAU - CRPDA ETE 2008 - ICP 8000 - + CRFPA - - Liberté publiques - Cours - - - Note de synthèse - Corrections - - - Droit civil - Cours - - - Droit civil - Corrections - - - Procédure administrative et contentieuse - Cours - - - Procédure administrative et contentieuse - Corrections - - - Procédure civile - Cours - - - Procédure civile - Corrections - - - Procédure pénale - Cours - - - Procédure pénale - Corrections - - - Droit commercial des affaires - Cours - - - Droit commercial des affaires - Corrections - - - Droit communautaire et européen - Cours - - - Droit communautaire et européen - Corrections - - - Droit fiscal - Cours - - - Droit fiscal - Corrections - - - Droit pénal - Cours - - - Droit pénal - Corrections - - - Droit de la famille et des personnes - Cours - - - Droit de la famille et des personnes - Corrections - - - Droit patrimonial - Cours - - - Droit patrimonial - Corrections - - - Droit du travail - Cours - - - Droit du travail - Corrections - - - Droit administratif - Cours - - - Droit administratif - Corrections - - - Droit public des activités économiques - Cours - - - Droit public des activités économiques - Corrections - - - Droit international privé - Cours - - - Droit international privé - Corrections - - - Procédures collectives et sûretés - Cours - - - Procédures collectives et sûretés - Corrections - - - Procédure communautaire - Cours - - - Procédures civile d'exécution - Cours - - - Comptabilité privée - Cours - - - Finances publiques - Cours - - - REUNION - - - TEST - + + Droit_administratif_Corrections + + + Droit_administratif_Cours + + + Droit_civil_Corrections + + + Droit_civil_Cours + + + Droit_commercial_des_affaires_Corrections + + + Droit_commercial_des_affaires_Cours + + + Droit_communautaire_et_europeen_Corrections + + + Droit_communautaire_et_europeen_Cours + + + Droit_de_la_famille_et_des_personnes_Corrections + + + Droit_de_la_famille_et_des_personnes_Cours + + + Droit_du_travail_Corrections + + + Droit_du_travail_Cours + + + Droit_fiscal_Corrections + + + Droit_fiscal_Cours + + + Droit_international_prive_Corrections + + + Droit_international_prive_Cours + + + Droit_patrimonial_Corrections + + + Droit_patrimonial_Cours + + + Droit_public_des_activites_economiques_Corrections + + + Droit_public_des_activites_economiques_Cours + + + Droit_penal_Corrections + + + Droit_penal_Cours + + + Libertes_publiques_Cours + + + Note_de_synthese_Corrections + + + Procedure_administrative_et_contentieuse_Corrections + + + Procedure_administrative_et_contentieuse_Cours + + + Procedure_civile_Corrections + + + Procedure_civile_Cours + + + Procedures_collectives_et_suretes_Corrections + + + Procedures_collectives_et_suretes_Cours + + + Procedure_penale_Corrections + + + Procedure_penale_Cours + + + TEST + + @@ -202,4 +188,5 @@ - + + diff --git a/etc/telecaster.cfg b/etc/telecaster.cfg new file mode 100644 index 0000000..4a10aca --- /dev/null +++ b/etc/telecaster.cfg @@ -0,0 +1,24 @@ +Server=localhost +Port=8000 +ServerPassword=source2parisson +ServerMountpoint=/Default_School_-_CRFPA_-_Droit_fiscal_Cours.ogg +ServerPublic=0 +AutomaticReconnectSecs=10 +Encode=OggVorbis +BitrateNominal=512 +NumberChannels=1 +OggQuality=1 +Samplerate=44100 +ServerType=Icecast2 +ExternalFile=/tmp +#YP Settings +ServerStreamURL=http://www.pre-barreau.com +ServerName=Default_School_-_CRFPA_-_Droit_fiscal_Cours +ServerDescription=Default_School_-_CRFPA_-_Droit_fiscal_Cours_-_1_-_azd_-_azd +ServerGenre=Teaching +#Advanced Settings +LogLevel=1 +LogFile=oddcastv3.log +SaveAsWAV=0 +OutputControl=SERVER,GENERAL,OUTPUT + diff --git a/etc/telecaster.xml b/etc/telecaster.xml new file mode 100644 index 0000000..d6beea5 --- /dev/null +++ b/etc/telecaster.xml @@ -0,0 +1,28 @@ + + + Default School + Default School + A school where you can learn + http://mydomain.com + Other + 1 + + + localhost + 8000 + source2parisson + 1 + /var/www/telecaster/ + etc/telecaster.cfg + lock/telecaster.lock + + + /tmp/media + ogg + 64 + 2 + 44100 + 2 + 1 + + diff --git a/etc/teleoddcast.cfg b/etc/teleoddcast.cfg index 2da2913..0565821 100644 --- a/etc/teleoddcast.cfg +++ b/etc/teleoddcast.cfg @@ -1,7 +1,7 @@ Server=localhost Port=8000 ServerPassword=source2parisson -ServerMountpoint=/Default_School_-_Computer_-_Conference_2.ogg +ServerMountpoint=/Default_School_-_AE_-_Administratif_Cours.ogg ServerPublic=0 AutomaticReconnectSecs=10 Encode=OggVorbis @@ -13,8 +13,8 @@ ServerType=Icecast2 ExternalFile=/tmp #YP Settings ServerStreamURL=http://www.pre-barreau.com -ServerName=Default_School_-_Computer_-_Conference_2 -ServerDescription=Default_School_-_Computer_-_Conference_2_-_2_-_azfpoh_-_opij +ServerName=Default_School_-_AE_-_Administratif_Cours +ServerDescription=Default_School_-_AE_-_Administratif_Cours_-_1_-_jf_-_jyf ServerGenre=Teaching #Advanced Settings LogLevel=1 diff --git a/telecaster.py b/telecaster.py new file mode 100755 index 0000000..ccc123a --- /dev/null +++ b/telecaster.py @@ -0,0 +1,435 @@ +#!/usr/bin/python +# *-* coding: utf-8 *-* +""" + telecaster + + 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. +""" + +version = '0.3.2' + +import os +import cgi +import shutil +import datetime +import time +import codecs +import string +import signal +from tools import * +from mutagen.oggvorbis import OggVorbis + + +class Conference: + """A conference object including metadata""" + + def __init__(self, dict): + self.title = dict['title'] + self.department = dict['department'] + self.conference = dict['conference'] + self.session = dict['session'] + self.professor = dict['professor'] + self.comment = dict['comment'] + + def get_info(self): + return self.title, self.department, self.conference, self.session, self.professor, self.comment + + +class Station(Conference): + """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, conference_dict, lock_file): + Conference.__init__(self, conference_dict) + self.date = datetime.datetime.now().strftime("%Y") + self.conf = xml2dict(conf_file) + self.conf = self.conf['telecaster'] + self.root_dir = self.conf['server']['root_dir'] + self.media_dir = self.conf['media']['dir'] + self.host = self.conf['server']['host'] + self.port = self.conf['server']['port'] + self.password = self.conf['server']['sourcepassword'] + self.url = 'http://'+self.host+':'+self.port + self.odd_conf_file = self.conf['server']['odd_conf_file'] + self.description = [self.title, self.department, self.conference, self.session, self.professor, self.comment] + self.server_name = [self.title, self.department, self.conference] + self.ServerDescription = clean_string('_-_'.join(self.description)) + self.ServerName = clean_string('_-_'.join(self.server_name)) + self.mount_point = '/' + clean_string(self.title) + '_-_' + \ + clean_string(self.department) + '_-_' + \ + clean_string(self.conference)+'.ogg' + self.lock_file = self.root_dir + os.sep + self.conf['server']['lock_file'] + self.filename = self.ServerDescription + '.ogg' + self.output_dir = self.media_dir + os.sep + self.department + os.sep + self.date + self.file_dir = self.output_dir + os.sep + self.ServerName + 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.bitrate = '64' + self.new_title = clean_string('_-_'.join(self.server_name)+'_-_'+self.professor+'_-_'+self.comment) + self.genre = 'Vocal' + self.encoder = 'TeleCaster by Parisson' + + 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') + + elif 'ServerPassword' in line.split('='): + newlines.append('ServerPassword=' + self.password + '\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.conference)[0:16]+'" -c '+self.odd_conf_file+ \ + ' alsa_pcm:capture_1 alsa_pcm:capture_2 > /dev/null &' + os.system(command) + self.set_lock() + time.sleep(1) + + def set_lock(self): + lock = open(self.lock_file,'w') + lock_text = clean_string('_*_'.join(self.description)) + 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): + if not os.path.exists(self.output_dir): + os.makedirs(self.output_dir) + command = 'streamripper ' + self.url + self.mount_point + \ + ' -d '+self.output_dir+' -D "%S" -s -t --quiet > /dev/null &' + os.system(command) + + def stop_oddcast(self): + if len(self.odd_pid) != 0: + os.system('kill -9 '+self.odd_pid[0]) + + def stop_rip(self): + if len(self.rip_pid) != 0: + os.system('kill -9 ' + self.rip_pid[0]) + time.sleep(1) + date = datetime.datetime.now().strftime("%Y") + if os.path.exists(self.file_dir) and os.path.exists(self.file_dir + os.sep + 'incomplete'): + shutil.move(self.file_dir+os.sep+'incomplete'+os.sep+' - .ogg', self.file_dir+os.sep) + shutil.rmtree(self.file_dir+os.sep+'incomplete'+os.sep) + os.rename(self.file_dir+os.sep+' - .ogg', self.file_dir+os.sep+self.filename) + + def mp3_convert(self): + os.system('oggdec -o - '+ self.file_dir+os.sep+self.filename+' | lame -S -m m -h -b '+ self.bitrate + \ + ' --add-id3v2 --tt "'+ self.new_title + '" --ta "'+self.professor+'" --tl "'+self.title+'" --ty "'+self.date+ \ + '" --tg "'+self.genre+'" - ' + self.file_dir+os.sep+self.ServerDescription + '.mp3 &') + + def write_tags(self): + file = self.file_dir + os.sep + self.filename + if os.path.exists(file): + audio = OggVorbis(file) + audio['TITLE'] = self.new_title + audio['ARTIST'] = self.professor + audio['ALBUM'] = self.title + audio['DATE'] = self.date + audio['GENRE'] = self.genre + audio['SOURCE'] = self.title + audio['ENCODER'] = self.encoder + 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() + self.encode_mp3() + + def encode_mp3(self): + self.mp3_convert() + + def start_mp3cast(self): + item_id = item_id + source = source + metadata = metadata + args = get_args(options) + ext = get_file_extension() + args = ' '.join(args) + command = 'sox "%s" -q -w -r 44100 -t wav -c2 - | lame %s -' \ + % (source, args) + # Processing (streaming + cache writing) + stream = self.core_process(self.command,self.buffer_size,self.dest) + for chunk in stream: + yield chunk + + def core_process(self, command, buffer_size, dest): + """Encode and stream audio data through a generator""" + __chunk = 0 + file_out = open(dest,'w') + try: + proc = subprocess.Popen(command, + shell = True, + bufsize = buffer_size, + stdin = subprocess.PIPE, + stdout = subprocess.PIPE, + close_fds = True) + except: + raise ExportProcessError('Command failure:', command, proc) + # Core processing + while True: + __chunk = proc.stdout.read(buffer_size) + status = proc.poll() + if status != None and status != 0: + raise ExportProcessError('Command failure:', command, proc) + if len(__chunk) == 0: + break + yield __chunk + file_out.write(__chunk) + file_out.close() + + +class WebView: + """Gives the web CGI frontend""" + + def __init__(self, school_file): + self.conf = xml2dict(school_file) + self.conf = self.conf['telecaster'] + self.url = self.conf['url'] + self.port = self.conf['port'] + self.title = self.conf['title'] + self.departments = self.conf['department'] + #print self.departments + #self.conferences = self.conf['department']['conferences'] + self.len_departments = len(self.departments) + self.conference_nb_max = 40 + + def header(self): + # Required header that tells the browser how to render the HTML. + print "Content-Type: text/html\n" + print "" + print "" + print "TeleCaster - "+self.title+"" + print "" + print '' + print "" + + print "" + print "
" + print "
" + print "

 TeleCaster - L'enregistrement et la diffusion audio en direct par internet

" + print "
" + + def colophon(self): + date = datetime.datetime.now().strftime("%Y") + print "
" + print "TeleCaster "+version+" © "+date+" Parisson. Tous droits réservés." + print "
" + + def footer(self): + print "
" + print "" + print "" + + def start_form(self, message=''): + self.header() + print "
" + print "
"+message+"
" + print "
Attention, il est important de remplir tous les champs, y compris le commentaire !
" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "
Titre :"+self.title+"
Département :
Conférence :
Session :
Professeur :
Commentaire :
" + print "
Cliquez ici pour écouter le flux continu 24/24 en direct
" + print "
" + print "
" + print "" + print "" + print "" + print "
" + self.colophon() + self.footer() + + def encode_form(self, message=''): + self.header() + print "
" + print "
"+message+"
" + print "
ENCODAGE EN COURS !
" + print "
" + self.colophon() + self.footer() + + def stop_form(self, conference_dict): + """Stop page""" + department = conference_dict['department'] + conference = conference_dict['conference'] + session = conference_dict['session'] + professor = conference_dict['professor'] + comment = conference_dict['comment'] + + self.header() + print "
" + print "

Cette formation est en cours de diffusion :

" + print "
" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "" + print "
Titre :"+self.title+"
Département :"+department+"
Conference :"+conference+"
Session :"+session+"
Professeur :"+professor+"
Commentaire :"+comment+"
" + print "
" + print "
Cliquez ici pour écouter cette formation en direct
" + print "
" + print "
" + print "" + print "" + print "" + print "
" + self.colophon() + self.footer() + + +class TeleCaster: + """Manage the calls of Station and Webview to get the network and + disk streams""" + + def __init__(self, conf_file, school_file): + """Main function""" + self.conf_file = conf_file + self.school_file = school_file + conf_t = xml2dict(self.conf_file) + self.conf = conf_t['telecaster'] + self.title = self.conf['infos']['name'] + self.root_dir = self.conf['server']['root_dir'] + self.lock_file = self.root_dir + os.sep + self.conf['server']['lock_file'] + self.odd_conf_file = self.conf['server']['lock_file'] + self.title = self.conf['infos']['name'] + self.uid = os.getuid() + self.odd_pid = get_pid('^oddcastv3 -n [^LIVE]', self.uid) + + def main(self): + w = WebView(self.school_file) + form = cgi.FieldStorage() + + if self.odd_pid == [] and form.has_key("action") and \ + form.has_key("department") and form.has_key("conference") and \ + form.has_key("professor") and form.has_key("comment") and \ + form["action"].value == "start": + + self.conference_dict = {'title': self.title, + 'department': form["department"].value, + 'conference': form["conference"].value, + 'session': form["session"].value, + 'professor': form["professor"].value, + 'comment': form["comment"].value} + + s = Station(self.conf_file, self.conference_dict, self.lock_file) + s.start() + w.stop_form(self.conference_dict) + + elif self.odd_pid != [] and os.path.exists(self.lock_file) and not form.has_key("action"): + self.conference_dict = get_conference_from_lock(self.lock_file) + w.stop_form(self.conference_dict) + + elif self.odd_pid != [] and form.has_key("action") and form["action"].value == "stop": + if os.path.exists(self.lock_file): + self.conference_dict = get_conference_from_lock(self.lock_file) + s = Station(self.conf_file, self.conference_dict, self.lock_file) + s.stop() + #w.encode_form() + #s.encode_mp3() + #w.start_form('Please wait : encoding file to MP3...') + w.start_form() + + elif self.odd_pid == []: + w.start_form() + + +# Call main function. +conf_file = 'etc/telecaster.xml' +school_file = 'etc/pre-barreau_conferences.xml' + +if __name__ == '__main__': + t = TeleCaster(conf_file, school_file) + t.main() + diff --git a/teleoddcast.py b/teleoddcast.py index 6507106..a8202d3 100755 --- a/teleoddcast.py +++ b/teleoddcast.py @@ -1,7 +1,7 @@ #!/usr/bin/python # *-* coding: utf-8 *-* """ - teleoddcast + telecaster Copyright (c) 2006-2007 Guillaume Pellerin @@ -29,6 +29,7 @@ import datetime import time import codecs import string +import signal from tools import * from mutagen.oggvorbis import OggVorbis @@ -56,7 +57,7 @@ class Station(Conference): Conference.__init__(self, conference_dict) self.date = datetime.datetime.now().strftime("%Y") self.conf = xml2dict(conf_file) - self.conf = self.conf['teleoddcast'] + self.conf = self.conf['telecaster'] self.root_dir = self.conf['server']['root_dir'] self.media_dir = self.conf['media']['dir'] self.host = self.conf['server']['host'] @@ -76,12 +77,12 @@ class Station(Conference): self.output_dir = self.media_dir + os.sep + self.department + os.sep + self.date self.file_dir = self.output_dir + os.sep + self.ServerName self.uid = os.getuid() - self.odd_pid = get_pid('^oddcastv3 -n [^LIVE]', self.uid) + self.odd_pid = get_pid('oddcastv3 -n', self.uid) self.rip_pid = get_pid('streamripper ' + self.url + self.mount_point, self.uid) self.bitrate = '64' self.new_title = clean_string('_-_'.join(self.server_name)+'_-_'+self.professor+'_-_'+self.comment) self.genre = 'Vocal' - self.encoder = 'TeleOddCast by Parisson' + self.encoder = 'TeleCaster by Parisson' def set_oddcast_conf(self): oddconf = open(self.odd_conf_file,'r') @@ -135,7 +136,7 @@ class Station(Conference): def stop_oddcast(self): if len(self.odd_pid) != 0: - os.system('kill -9 ' + self.odd_pid[0]) + os.system('kill -9 '+self.odd_pid[0]) def stop_rip(self): if len(self.rip_pid) != 0: @@ -224,7 +225,7 @@ class WebView: def __init__(self, school_file): self.conf = xml2dict(school_file) - self.conf = self.conf['teleoddcast'] + self.conf = self.conf['telecaster'] self.url = self.conf['url'] self.port = self.conf['port'] self.title = self.conf['title'] @@ -239,8 +240,8 @@ class WebView: print "Content-Type: text/html\n" print "" print "" - print "TeleOddCast - "+self.title+"" - print "" + print "TeleCaster - "+self.title+"" + print "" print '