From c68f4a42b4e73e2847a9fab288a74091587fe16f Mon Sep 17 00:00:00 2001 From: achbed Date: Tue, 27 Jan 2015 17:13:47 -0600 Subject: [PATCH] New MediaBase class for common media object functionality Refactored MP3, OGG, WebM classes to use MediaBase Station now uses common MediaBase functions to get artist, title, and song info --- deefuzzer/station.py | 106 +++++++++++++---------------- deefuzzer/tools/__init__.py | 1 + deefuzzer/tools/mediabase.py | 127 +++++++++++++++++++++++++++++++++++ deefuzzer/tools/mp3.py | 58 +++++----------- deefuzzer/tools/ogg.py | 83 +++++++++-------------- deefuzzer/tools/webm.py | 13 ++-- 6 files changed, 230 insertions(+), 158 deletions(-) create mode 100644 deefuzzer/tools/mediabase.py diff --git a/deefuzzer/station.py b/deefuzzer/station.py index 4cef3fa..1e2ae72 100644 --- a/deefuzzer/station.py +++ b/deefuzzer/station.py @@ -95,6 +95,8 @@ class Station(Thread): self.logqueue = logqueue self.m3u = m3u + self.current_media_obj = MediaBase() + if 'station_statusfile' in self.station: self.statusfile = station['station_statusfile'] try: @@ -452,24 +454,12 @@ class Station(Thread): if len(self.new_tracks): new_tracks_objs = self.media_to_objs(self.new_tracks) for media_obj in new_tracks_objs: - title = '' - artist = '' - if 'title' in media_obj.metadata: - title = media_obj.metadata['title'] - if 'artist' in media_obj.metadata: - artist = media_obj.metadata['artist'] - if not (title or artist): - song = str(media_obj.file_name) - else: - song = artist + ' - ' + title - - song = song.encode('utf-8') - artist = artist.encode('utf-8') + title, artist, song = self.get_songmeta(media_obj) artist_names = artist.split(' ') artist_tags = ' #'.join(list(set(artist_names) - {'&', '-'})) - message = '#NEWTRACK ! %s #%s on #%s RSS: ' % \ - (song.replace('_', ' '), artist_tags, self.short_name) + message = '#NEWTRACK ! %s %s on #%s' % \ + (song, artist_tags.strip(), self.short_name) message = message[:113] + self.feeds_url self.update_twitter(message) @@ -547,30 +537,20 @@ class Station(Thread): def media_to_objs(self, media_list): media_objs = [] for media in media_list: + file_meta = MediaBase() file_name, file_title, file_ext = get_file_info(media) self.q.get(1) try: if file_ext.lower() == 'mp3' or mimetypes.guess_type(media)[0] == 'audio/mpeg': - try: - file_meta = Mp3(media) - except: - continue + file_meta = Mp3(media) elif file_ext.lower() == 'ogg' or mimetypes.guess_type(media)[0] == 'audio/ogg': - try: - file_meta = Ogg(media) - except: - continue + file_meta = Ogg(media) elif file_ext.lower() == 'webm' or mimetypes.guess_type(media)[0] == 'video/webm': - try: - file_meta = WebM(media) - except: - continue - if self.feeds_showfilename: - file_meta.metadata['filename'] = file_name.decode("utf-8") # decode needed for some weird filenames - if self.feeds_showfilepath: - file_meta.metadata['filepath'] = media.decode("utf-8") # decode needed for some weird filenames + file_meta = WebM(media) except: pass + file_meta.metadata['filename'] = file_name.decode("utf-8") # decode needed for some weird filenames + file_meta.metadata['filepath'] = media.decode("utf-8") # decode needed for some weird filenames self.q.task_done() media_objs.append(file_meta) return media_objs @@ -602,18 +582,16 @@ class Station(Thread): for key in media.metadata.keys(): if media.metadata[key] != '': + if key == 'filepath' and not self.feeds_showfilepath: + continue + if key == 'filename' and not self.feeds_showfilename: + continue media_description += media_description_item % (key.capitalize(), media.metadata[key]) json_item[key] = media.metadata[key] media_description += '' - title = media.metadata['title'] - artist = media.metadata['artist'] - if not (title or artist): - song = str(media.file_title) - else: - song = artist + ' - ' + title - + title, artist, song = self.get_songmeta(media) media_absolute_playtime += media.length if self.feeds_enclosure == '1': @@ -674,11 +652,7 @@ class Station(Thread): def set_relay_mode(self): self.prefix = '#nowplaying #LIVE' - self.title = self.channel.description.encode('utf-8') - self.artist = self.relay_author.encode('utf-8') - self.title = self.title.replace('_', ' ') - self.artist = self.artist.replace('_', ' ') - self.song = self.artist + ' - ' + self.title + self.get_currentsongmeta() if self.type == 'stream-m': relay = URLReader(self.relay_url) @@ -688,28 +662,40 @@ class Station(Thread): else: self.stream = self.player.relay_read() - def set_read_mode(self): - self.prefix = '#nowplaying' - self.current_media_obj = self.media_to_objs([self.media]) + def get_songmeta(self, mediaobj): + title = "" + artist = "" + song = "" + try: - self.title = self.current_media_obj[0].metadata['title'] - self.artist = self.current_media_obj[0].metadata['artist'] + title = mediaobj.get_title() + artist = mediaobj.get_artist() + song = mediaobj.get_song(True) except: - self.title = 'title' - self.artist = 'artist' + pass - self.title = self.title.replace('_', ' ') - self.artist = self.artist.replace('_', ' ') + return title, artist, song - if not (self.title or self.artist): - song = str(self.current_media_obj[0].file_name) - else: - song = self.artist + ' - ' + self.title + def get_currentsongmeta(self): + self.title = "" + self.artist = "" + self.song = "" + self.current_media_obj = MediaBase() + + try: + m = self.media_to_objs([self.media]) + self.current_media_obj = m[0] + except: + pass + + self.title, self.artist, self.song = self.get_songmeta(self.current_media_obj) + + def set_read_mode(self): + self.prefix = '#nowplaying' + self.get_currentsongmeta() - self.song = song.encode('utf-8') - self.artist = self.artist.encode('utf-8') self.metadata_file = self.metadata_dir + os.sep + self.current_media_obj[0].file_name + '.xml' - self.update_feeds(self.current_media_obj, self.feeds_current_file, '(currently playing)') + self.update_feeds([self.current_media_obj], self.feeds_current_file, '(currently playing)') self._info('DeeFuzzing: id = %s, name = %s' % (self.id, self.current_media_obj[0].file_name)) self.player.set_media(self.media) @@ -730,8 +716,6 @@ class Station(Thread): def update_twitter_current(self): if not self.__twitter_should_update(): return - # artist_names = self.artist.split(' ') - # artist_tags = ' #'.join(list(set(artist_names) - {'&', '-'})) message = '%s %s on #%s' % (self.prefix, self.song, self.short_name) tags = '#' + ' #'.join(self.twitter_tags) message = message + ' ' + tags diff --git a/deefuzzer/tools/__init__.py b/deefuzzer/tools/__init__.py index 6dc964d..276c198 100644 --- a/deefuzzer/tools/__init__.py +++ b/deefuzzer/tools/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from xmltodict import * from PyRSS2Gen import * +from mediabase import * from mp3 import * from ogg import * from webm import * diff --git a/deefuzzer/tools/mediabase.py b/deefuzzer/tools/mediabase.py new file mode 100644 index 0000000..4474e63 --- /dev/null +++ b/deefuzzer/tools/mediabase.py @@ -0,0 +1,127 @@ +__author__ = 'Dennis Wallace' + +import tempfile + +class MediaBase(object): + """Base Media class. All media objects should inherit from this class + to allow common functions to be used in core code. See MP3 and OGG classes + for examples on how to configure a subclass.""" + + def __init__(self): + object.__init__(self) + + # Set the following five values in an inherited subclass. + + # A text string describing this media type + self.description = '' + + # A text string declaring the MIME Type for this media type + self.mime_type = '' + + # A text string declaring the common file extension for this media type + self.extension = '' + + # A text string declaring the media format. The self.format property + # should be unique across all subclasses inherited from MediaBase. + self.format = '' + + # tagdata contains a dictionary of tags to use to gather metadata from the sourceobj + self.tagdata = {} + + self.media = None + self.item_id = '' + self.source = None + self.options = {} + self.bitrate_default = 0 + self.info = None + self.bitrate = 0 + self.length = 0 + self.metadata = { + 'title': '', + 'artist': '', + 'album': '', + 'date': '', + 'comment': '', + 'country': '', + 'genre': '', + 'copyright': '' + } + + # sourceobj contains the metadata information for the referenced object + self.sourceobj = {} + + self.media_info = [] + self.file_name = '' + self.file_title = '' + self.file_ext = '' + self.size = 0 + + # A more cross-platform way to do this + self.cache_dir = tempfile.gettempdir() + + def get_format(self): + """Gets the format string of the media type""" + return self.format + + def get_file_extension(self): + """Gets the actual file extension string of the media""" + return self.file_ext + + def get_mime_type(self): + """Gets the MIME Type string for this media type""" + return self.mime_type + + def get_description(self): + """Gets the description string for this media type""" + return self.description + + def set_cache_dir(self, path): + """Sets an alternate location for temporary cache files used in this media object""" + self.cache_dir = path + + def get_file_metadata(self): + """Returns the metadata for the media, filtered by the tagdata dictionary for this media type""" + metadata = {} + for key in self.tagdata.keys(): + metadata[key] = '' + try: + metadata[key] = self.sourceobj[key][0] + except: + try: + if self.tagdata[key] != '': + metadata[key] = self.sourceobj[self.tagdata[key]][0] + except: + pass + return metadata + + def __get_metadata_value(self, key, clean=False): + """Returns a metadata value for a give key. If clean is True, then the resulting string will + be cleaned before it is returned. If the key does not exist, an empty string is returned.""" + if key not in self.metadata: + return '' + r = self.metadata[key] + if clean: + r = r.replace('_',' ').strip() + return r.encode('utf-8') + + def get_title(self): + """Returns the cleaned title for this media""" + return self.__get_metadata_value('title', True) + + def get_artist(self): + """Returns the cleaned artist for this media""" + return self.__get_metadata_value('artist', True) + + def get_song(self, usefn=True): + """Returns a string in the form "artist - title" for this media. If either artist or title are blank, + only the non-blank field is returned. If both fields are blank, and the usefn parameter is True, then + the filename is returned instead. Otherwise, an empty string is returned.""" + a = self.__get_metadata_value('artist', True) + t = self.__get_metadata_value('title', True) + if len(a) == 0 and len(t) == 0 and usefn: + a = self.file_name.encode('utf-8') + r = a + if len(a) > 0 and len(t) > 0: + r += ' - ' + r += t + return r diff --git a/deefuzzer/tools/mp3.py b/deefuzzer/tools/mp3.py index 4581300..fbb1020 100644 --- a/deefuzzer/tools/mp3.py +++ b/deefuzzer/tools/mp3.py @@ -50,17 +50,21 @@ EasyID3.valid_keys["country"] = "TXXX:COUNTRY:'XXX'" EasyID3.RegisterTXXXKey("country", "COUNTRY") -class Mp3: +class Mp3(MediaBase): """A MP3 file object""" - def __init__(self, media): - self.media = media - self.item_id = '' + def __init__(self, newmedia): + MediaBase.__init__(self) + + self.description = "MPEG audio Layer III" + self.mime_type = 'audio/mpeg' + self.extension = 'mp3' + self.format = 'MP3' + + self.media = newmedia self.source = self.media - self.options = {} self.bitrate_default = 192 - self.cache_dir = os.sep + 'tmp' - self.keys2id3 = { + self.tagdata = { 'title': 'TIT2', 'artist': 'TPE1', 'album': 'TALB', @@ -70,8 +74,8 @@ class Mp3: 'genre': 'TCON', 'copyright': 'TCOP' } - self.mp3 = MP3(self.media, ID3=EasyID3) - self.info = self.mp3.info + self.sourceobj = MP3(self.media, ID3=EasyID3) + self.info = self.sourceobj.info self.bitrate = self.bitrate_default try: self.bitrate = int(self.info.bitrate / 1024) @@ -92,47 +96,19 @@ class Mp3: 'copyright': '' } - self.description = self.get_description() - self.mime_type = self.get_mime_type() self.media_info = get_file_info(self.media) self.file_name = self.media_info[0] self.file_title = self.media_info[1] self.file_ext = self.media_info[2] - 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' - - def get_mime_type(self): - return 'audio/mpeg' - - def get_description(self): - return "MPEG audio Layer III" - - def get_file_metadata(self): - metadata = {} - for key in self.keys2id3.keys(): - try: - metadata[key] = self.mp3[key][0] - except: - try: - metadata[key] = self.mp3[self.keys2id3[key]][0] - except: - metadata[key] = '' - return metadata + self.size = os.path.getsize(mediabase) def write_tags(self): """Write all ID3v2.4 tags by mapping dub2id3_dict dictionnary with the respect of mutagen classes and methods""" - self.mp3.add_tags() - self.mp3.tags['TIT2'] = id3.TIT2(encoding=2, text=u'text') - self.mp3.save() + self.sourceobj.add_tags() + self.sourceobj.tags['TIT2'] = id3.TIT2(encoding=2, text=u'text') + self.sourceobj.save() ''' # media_id3 = id3.ID3(self.media) diff --git a/deefuzzer/tools/ogg.py b/deefuzzer/tools/ogg.py index a970f8a..c9834c8 100644 --- a/deefuzzer/tools/ogg.py +++ b/deefuzzer/tools/ogg.py @@ -43,55 +43,45 @@ from mutagen.oggvorbis import OggVorbis from utils import * -class Ogg: +class Ogg(MediaBase): """An OGG file object""" def __init__(self, media): + MediaBase.__init__(self) + + self.description = "OGG Vorbis" + self.mime_type = 'audio/ogg' + self.extension = 'ogg' + self.format = 'OGG' + self.media = media - self.ogg = OggVorbis(self.media) - self.item_id = '' + self.sourceobj = OggVorbis(self.media) self.source = self.media - self.options = {} self.bitrate_default = '192' - self.cache_dir = os.sep + 'tmp' - self.keys2ogg = { - 'title': 'title', - 'artist': 'artist', - 'album': 'album', - 'date': 'date', - 'comment': 'comment', - 'genre': 'genre', - 'copyright': 'copyright' + + self.tagdata = { + 'title': '', + 'artist': '', + 'album': '', + 'date': '', + 'comment': '', + 'genre': '', + 'copyright': '' } - self.info = self.ogg.info + + self.info = self.sourceobj.info self.bitrate = int(str(self.info.bitrate)[:-3]) self.length = datetime.timedelta(0, self.info.length) self.metadata = self.get_file_metadata() - self.description = self.get_description() - self.mime_type = self.get_mime_type() self.media_info = get_file_info(self.media) self.file_name = self.media_info[0] self.file_title = self.media_info[1] self.file_ext = self.media_info[2] - self.extension = self.get_file_extension() self.size = os.path.getsize(media) - # self.args = self.get_args() - - def get_format(self): - return 'OGG' - - def get_file_extension(self): - return 'ogg' - - def get_mime_type(self): - return 'audio/ogg' - - def get_description(self): - return 'OGG Vorbis' def get_file_info(self): try: - file_out1, file_out2 = os.popen4('ogginfo "' + self.dest + '"') + file_out1, file_out2 = os.popen4('ogginfo "' + self.source + '"') info = [] for line in file_out2.readlines(): info.append(clean_word(line[:-1])) @@ -100,31 +90,21 @@ class Ogg: except: raise IOError('ExporterError: file does not exist.') - def set_cache_dir(self, path): - self.cache_dir = path - - def get_file_metadata(self): - metadata = {} - for key in self.keys2ogg.keys(): - try: - metadata[key] = self.ogg[key][0] - except: - metadata[key] = '' - return metadata - def decode(self): + if not self.item_id: + raise IOError('ExporterError: Required item_id parameter not set.') try: - os.system('oggdec -o "' + self.cache_dir + os.sep + self.item_id + - '.wav" "' + self.source + '"') - return self.cache_dir + os.sep + self.item_id + '.wav' + p = os.path.join(self.cache_dir, (self.item_id + '.wav')) + os.system('oggdec -o "' + p + '" "' + self.source + '"') + return p except: raise IOError('ExporterError: decoder is not compatible.') def write_tags(self): # self.ogg.add_tags() for tag in self.metadata.keys(): - self.ogg[tag] = str(self.metadata[tag]) - self.ogg.save() + self.sourceobj[tag] = str(self.metadata[tag]) + self.sourceobj.save() def get_args(self, options=None): """Get process options and return arguments for the encoder""" @@ -145,8 +125,9 @@ class Ogg: for tag in self.metadata.keys(): value = clean_word(self.metadata[tag]) args.append('-c %s="%s"' % (tag, value)) - if tag in self.dub2args_dict: - arg = self.dub2args_dict[tag] - args.append('-c %s="%s"' % (arg, value)) + if tag in self.tagdata: + arg = self.tagdata[tag] + if arg: + args.append('-c %s="%s"' % (arg, value)) return args diff --git a/deefuzzer/tools/webm.py b/deefuzzer/tools/webm.py index 389149d..fc7d25e 100644 --- a/deefuzzer/tools/webm.py +++ b/deefuzzer/tools/webm.py @@ -42,15 +42,18 @@ import datetime from utils import * -class WebM(object): +class WebM(MediaBase): """An WebM file object""" def __init__(self, media): - self.media = media - self.item_id = '' - self.source = self.media + MediaBase.__init__(self) + + self.description = "WebM" self.mime_type = 'video/webm' self.extension = 'webm' - self.description = 'WebM' + self.format = 'WebM' + + self.media = media + self.source = self.media self.metadata = {} self.file_name, self.file_title, self.file_ext = get_file_info(media) -- 2.39.5