From e922416afeecc16ceb2d376530915e32e71ba2ac Mon Sep 17 00:00:00 2001 From: Guillaume Pellerin Date: Sat, 23 Jan 2010 02:33:39 +0000 Subject: [PATCH] add recoder, fix some id3 bugs --- README | 2 +- example/myfuzz.xml | 6 ++++++ tools/__init__.py | 1 + tools/mp3.py | 37 +++++++++++++++++++++---------------- tools/station.py | 44 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 70 insertions(+), 20 deletions(-) diff --git a/README b/README index c087094..ff36bbd 100644 --- a/README +++ b/README @@ -77,7 +77,7 @@ XML Configuration ================= See example/myfuzz.xml in a text editor. -The inline comments should help you to configure your stations +The inline comments should help you to configure your stations. OSC Control diff --git a/example/myfuzz.xml b/example/myfuzz.xml index 5a66f60..ca93321 100644 --- a/example/myfuzz.xml +++ b/example/myfuzz.xml @@ -89,6 +89,12 @@ http://anotherdomain.com:8000/stream.mp3 + + + 0 + + /path/to/archives + diff --git a/tools/__init__.py b/tools/__init__.py index 277bf18..cca19e3 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -6,6 +6,7 @@ from mp3 import * from ogg import * from logger import * from player import * +from recorder import * from osc import * from twitt import * from relay import * diff --git a/tools/mp3.py b/tools/mp3.py index 760797e..4599d89 100644 --- a/tools/mp3.py +++ b/tools/mp3.py @@ -9,16 +9,16 @@ # and video data through icecast2 servers. # This software is governed by the CeCILL license under French law and -# abiding by the rules of distribution of free software. You can use, +# abiding by the rules of distribution of free software. You can use, # modify and/ or redistribute the software under the terms of the CeCILL # license as circulated by CEA, CNRS and INRIA at the following URL -# "http://www.cecill.info". +# "http://www.cecill.info". # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited -# liability. +# liability. # In this respect, the user's attention is drawn to the risks associated # with loading, using, modifying and/or developing or reproducing the @@ -27,8 +27,8 @@ # therefore means that it is reserved for developers and experienced # professionals having in-depth computer knowledge. Users are therefore # encouraged to load and test the software's suitability as regards their -# requirements in conditions enabling the security of their systems and/or -# data to be ensured and, more generally, to use and operate it in the +# requirements in conditions enabling the security of their systems and/or +# data to be ensured and, more generally, to use and operate it in the # same conditions as regards security. # The fact that you are presently reading this means that you have had @@ -48,7 +48,7 @@ EasyID3.valid_keys["copyright"]="TCOP::'XXX'" class Mp3: """A MP3 file object""" - + def __init__(self, media): self.media = media self.item_id = '' @@ -78,10 +78,10 @@ class Mp3: self.extension = self.get_file_extension() self.size = os.path.getsize(media) #self.args = self.get_args() - + def get_format(self): return 'MP3' - + def get_file_extension(self): return 'mp3' @@ -90,7 +90,7 @@ class Mp3: def get_description(self): return "MPEG audio Layer III" - + def get_file_metadata(self): metadata = {} for key in self.keys2id3.keys(): @@ -111,25 +111,30 @@ class Mp3: def write_tags(self): """Write all ID3v2.4 tags by mapping dub2id3_dict dictionnary with the respect of mutagen classes and methods""" - id3 = id3.ID3(self.media) + from mutagen import id3 + m = MP3(self.media) + m.add_tags() + m.tags['TIT2'] = id3.TIT2(encoding=2, text=u'text') + m.save() + media = id3.ID3(self.media) for tag in self.metadata.keys(): - if tag in self.dub2id3_dict.keys(): - frame_text = self.dub2id3_dict[tag] + if tag in self.keys2id3.keys(): + frame_text = self.keys2id3[tag] value = self.metadata[tag] - frame = mutagen.id3.Frames[frame_text](3,value) + frame = id3.Frames[frame_text](3,value) try: - id3.add(frame) + media.add(frame) except: raise IOError('ExporterError: cannot tag "'+tag+'"') try: - id3.save() + media.save() except: raise IOError('ExporterError: cannot write tags') def get_args(self, options=None): """Get process options and return arguments for the encoder""" args = [] - if not options is None: + if not options is None: self.options = options if not ( 'verbose' in self.options and self.options['verbose'] != '0' ): args.append('-S') diff --git a/tools/station.py b/tools/station.py index 733a215..ebbf390 100644 --- a/tools/station.py +++ b/tools/station.py @@ -133,7 +133,7 @@ class Station(Thread): if self.relay_mode == 1: self.relay_callback('/relay', [1]) - # Twittering + # Twitting # mode = 0 means Off, mode = 1 means On self.twitter_mode = 0 if 'twitter' in self.station: @@ -146,7 +146,16 @@ class Station(Thread): self.tinyurl = tinyurl.create_one(self.channel.url + '/m3u/' + self.m3u.split(os.sep)[-1]) self.twitter_callback('/twitter', [1]) - # OSC + # Recording + # mode = 0 means Off, mode = 1 means On + self.record_mode = 0 + if 'record' in self.station: + self.record_mode = int(self.station['record']['mode']) + self.record_dir = self.station['record']['dir'] + if self.record_mode == 1: + self.record_callback('/write', [1]) + + # OSCing self.osc_control_mode = 0 # mode = 0 means Off, mode = 1 means On if 'control' in self.station: @@ -160,6 +169,8 @@ class Station(Thread): self.osc_controller.add_method('/media/relay', 'i', self.relay_callback) self.osc_controller.add_method('/twitter', 'i', self.twitter_callback) self.osc_controller.add_method('/jingles', 'i', self.jingles_callback) + self.osc_controller.add_method('/record', 'i', self.record_callback) + def media_next_callback(self, path, value): value = value[0] @@ -197,6 +208,25 @@ class Station(Thread): message = "Received OSC message '%s' with arguments '%d'" % (path, value) self.logger.write(message) + def record_callback(self, path, value): + value = value[0] + if value == 1: + self.rec_file = self.short_name + '-' + \ + datetime.datetime.now().strftime("%x-%X").replace('/', '_') + '.' + self.channel.format + self.recorder = Recorder(self.record_dir) + self.recorder.open(self.rec_file) + elif value == 0: + self.recorder.close() + if self.channel.format == 'mp3': + media = Mp3(self.record_dir + os.sep + self.rec_file) + if self.channel.format == 'ogg': + media = Ogg(self.record_dir + os.sep + self.rec_file) + media.metadata = {'artist': self.artist, 'title': self.title, 'date': str(datetime.datetime.now().strftime("%Y"))} + media.write_tags() + self.record_mode = value + message = "Received OSC message '%s' with arguments '%d'" % (path, value) + self.logger.write(message) + def get_playlist(self): file_list = [] for root, dirs, files in os.walk(self.media_dir): @@ -401,6 +431,7 @@ class Station(Thread): self.q.task_done() self.q.get(1) + if self.relay_mode == 1: self.set_relay_mode() elif os.path.exists(self.media) and not os.sep+'.' in self.media: @@ -420,9 +451,16 @@ class Station(Thread): if self.next_media == 1: break except: - self.logger.write('ERROR : Station ' + self.short_name + ' : could not send the buffer... ') + self.logger.write('ERROR : Station ' + self.short_name + ' : could not send the buffer to the server ') self.channel.close() self.channel.open() continue + try: + if self.record_mode == 1: + self.recorder.write(self.chunk) + except: + self.logger.write('ERROR : Station ' + self.short_name + ' : could not write the buffer to the file ') + continue self.q.task_done() + self.channel.close() -- 2.39.5