Changeset 298

Show
Ignore:
Timestamp:
06/10/06 21:08:58 (3 years ago)
Author:
nicfit
Message:

Added the ability to play remote files (http)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/audio_control.py

    r289 r298  
    9494        gobject.signal_new('prev', AudioControl, gobject.SIGNAL_RUN_LAST, 
    9595                           gobject.TYPE_NONE, []) 
    96         # Callback takes: widget, old_index, new_index 
    97         gobject.signal_new("source-changed", AudioControl, 
     96        gobject.signal_new('source-changed', AudioControl, 
    9897                           gobject.SIGNAL_RUN_LAST, 
    9998                           gobject.TYPE_NONE, 
    10099                           [gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]) 
    101         # Callback takes: widget, error_message, audio_source 
    102         gobject.signal_new("error", AudioControl, gobject.SIGNAL_RUN_LAST, 
     100        gobject.signal_new('error', AudioControl, gobject.SIGNAL_RUN_LAST, 
    103101                           gobject.TYPE_NONE, [gobject.TYPE_STRING, 
    104102                                               gobject.TYPE_PYOBJECT]) 
    105         gobject.signal_new("playlist-reset", AudioControl, 
     103        # Callback takes: widget, audio_src 
     104        gobject.signal_new('tag-update', AudioControl, gobject.SIGNAL_RUN_LAST, 
     105                           gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]) 
     106        gobject.signal_new('playlist-reset', AudioControl, 
    106107                           gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []) 
    107108 
     
    351352    def _set_source(self, src): 
    352353        self._set_track_scale(0.0) 
    353  
    354         if src.uri.scheme == 'file': 
    355             self._gst_bin.set_property('uri', src.uri.to_string()) 
    356         else: 
    357             raise RuntimeError("Unsupported URI scheme: " + src.uri.scheme) 
     354        self._gst_bin.set_property('uri', src.uri.to_string()) 
    358355        self._current_audio_src = src 
    359356 
     
    428425                                {'next': True, 'start_playing': True}) 
    429426        elif message.type == gst.MESSAGE_TAG: 
    430             # TODO: Read tags from streams 
    431             pass 
     427            if not self._current_audio_src.meta_data.frozen: 
     428                self._update_meta_data(self._current_audio_src, 
     429                                       message.parse_tag()) 
    432430        elif message.type == gst.MESSAGE_ERROR: 
    433431            self._gst_error_set = True 
     
    438436            self.emit('error', error, self._current_audio_src) 
    439437 
     438    def _update_meta_data(self, src, taglist): 
     439        '''Possible keys: 
     440        ['title', 'artist', 'album', 'date', 'track-count', 'track-number', 
     441         'genre', 'duration'] 
     442        ['layer', 'mode', 'emphasis', 'audio-codec', 'bitrate'] 
     443        ''' 
     444        changed = False 
     445        keys = taglist.keys() 
     446        if 'title' in keys: 
     447            src.meta_data.title = unicode(taglist['title'], 'utf-8') 
     448        if 'artist' in keys: 
     449            src.meta_data.artist = unicode(taglist['artist'], 'utf-8') 
     450        if 'album' in keys: 
     451            src.meta_data.album = unicode(taglist['album'], 'utf-8') 
     452        if 'date' in keys: 
     453            src.meta_data.year = unicode(str(taglist['date'].year), 'utf-8') 
     454        if 'track-number' in keys: 
     455            src.meta_data.track_num = taglist['track-number'] 
     456        if 'track-count' in keys: 
     457            src.meta_data.track_total = taglist['track-count'] 
     458        if 'duration' in keys: 
     459            src.audio_info.time_secs = taglist['duration'] / gst.SECOND 
     460        self.emit('tag-update', src) 
    440461 
    441462    ### Timer methods ### 
  • trunk/src/mesk/audio_source.py

    r178 r298  
    4242    year = None 
    4343    track_num = track_total = None 
     44    frozen = False 
    4445 
    4546    def __init__(self, native_tag = None): 
     
    5051        self.album = native_tag.getAlbum() or EMPTY_METADATA 
    5152        self.year = native_tag.getYear() 
    52         (self.track_num, self.track_total) = native_tag.getTrackNum() or 0 
     53        (self.track_num, self.track_total) = native_tag.getTrackNum() 
    5354 
    5455class AudioSource: 
     
    5657        if not isinstance(uri, Uri): 
    5758            self.uri = Uri(uri) 
     59        else: 
     60            self.uri = uri 
    5861        self.meta_data = None 
    5962        self.audio_info = AudioInfo() 
     
    6770            self.audio_info.time_secs = audio_file.getPlayTime() 
    6871            self.audio_info.size_bytes = audio_file.getSize() 
    69  
    7072            self.meta_data = AudioMetaData(audio_file.tag) 
    7173        except eyeD3.TagException, ex: 
     
    7577 
    7678        if not self.meta_data: 
     79            self.metadata = AudioMetaData() 
    7780            mesk.log.warning(_('No metadata for file \'%s\'') % self.uri.path) 
    78             pass 
     81        else: 
     82            self.meta_data.frozen = True 
    7983 
    80 # FIXME: Rename HttpAudioSource 
    81 class UrlAudioSource(AudioSource): 
    82     # TODO 
    83     def __init__(self, url): 
    84         AudioSource.__init__(self, url) 
     84class HttpAudioSource(AudioSource): 
     85    def __init__(self, http_uri): 
     86        AudioSource.__init__(self, http_uri) 
     87 
     88        self.audio_info.time_secs = None 
     89        self.audio_info.size_bytes = None 
     90        self.meta_data = AudioMetaData() 
     91        # FIXME: Make use of extended m3u data if possible 
     92        self.meta_data.title = unicode(self.uri.to_string()) 
    8593 
    8694class UnsupportedScheme(Exception): 
     
    96104    if uri.scheme == 'file': 
    97105        path = os.path.realpath(os.path.abspath(uri.path)) 
    98         ext = os.path.splitext(path) 
    99         if not ext or ext[1][1:] not in SUPPORTED_AUDIO: 
     106        ext = os.path.splitext(path)[1] 
     107        if not ext or ext[1:] not in SUPPORTED_AUDIO: 
    100108            mt = mimetypes.guess_type(path)[0] 
    101109            if not mt: 
     
    107115            mesk.log.error(_('Error loading source file %s') % path) 
    108116            src = None 
     117    elif uri.scheme == 'http' or uri.scheme == 'https': 
     118        # FIXME: Pass any extended m3u info 
     119        src = HttpAudioSource(uri) 
    109120    else: 
    110121        raise UnsupportedScheme(_('Unsupported audio URI scheme: %s') % \ 
  • trunk/src/mesk/playlist.py

    r285 r298  
    2323import audio_source 
    2424import utils 
     25import log 
    2526import common.uri 
    2627 
     
    4243        line = line.strip() 
    4344        if line[0] == '#': 
    44             # TODO: meta data can be extracted here (e.g. stream info) 
     45            # FIXME: meta data can be extracted here (e.g. stream info) 
    4546            continue 
    46         src = audio_source.load(line) 
    47         if src: 
    48             pl.append(src) 
     47        try: 
     48            src = audio_source.load(line) 
     49        except Exception, ex: 
     50            log.warn(str(ex)) 
     51        else: 
     52            if src: 
     53                pl.append(src) 
    4954    fp.close() 
    5055 
     
    5257    fp = file(pl_file, 'w') 
    5358    for src in pl: 
    54         fp.write(src.uri.path) 
     59        if src.uri.scheme == 'file': 
     60            fp.write(src.uri.path) 
     61        else: 
     62            fp.write(src.uri.to_string()) 
    5563        fp.write('\n') 
    5664    fp.close() 
  • trunk/src/mesk/utils.py

    r286 r298  
    2727def format_track_time(curr, total = None): 
    2828    def time_tuple(ts): 
     29        if ts is None or ts < 0: 
     30            ts = 0 
    2931        hours = ts / 3600 
    3032        mins = (ts % 3600) / 60 
  • trunk/src/playlist_control.py

    r273 r298  
    175175        self._audio_control.connect('error', self._on_audio_error) 
    176176        self._audio_control.connect('playlist-reset', self._on_playlist_reset) 
     177        self._audio_control.connect('tag-update', self._on_audio_tag_update) 
    177178 
    178179        self.widget.show() 
     
    195196        self._save_playlist() 
    196197 
    197     def _new_model_row(self, src): 
    198         filename = os.path.basename(src.uri.path) 
    199         filename = gtk_utils.escape_pango_markup(filename) 
    200         title = gtk_utils.escape_pango_markup(src.meta_data.title) 
    201         artist = gtk_utils.escape_pango_markup(src.meta_data.artist) 
    202         album = gtk_utils.escape_pango_markup(src.meta_data.album) 
    203         year = unicode(src.meta_data.year) 
     198    def _get_model_metadata(self, src): 
     199        row_data = {} 
     200        row_data[MODEL_TITLE] = \ 
     201          gtk_utils.escape_pango_markup(src.meta_data.title) 
     202        row_data[MODEL_ARTIST] = \ 
     203          gtk_utils.escape_pango_markup(src.meta_data.artist) 
     204        row_data[MODEL_ALBUM] = \ 
     205          gtk_utils.escape_pango_markup(src.meta_data.album) 
     206 
     207        if src.meta_data.year: 
     208            year = unicode(src.meta_data.year) 
     209        else: 
     210            year = u'' 
     211        row_data[MODEL_YEAR] = year 
     212 
    204213        track_num = src.meta_data.track_num 
    205214        if track_num is None: 
    206215            track_num = 0 
    207  
    208         return [MODEL_STATE_ACTIVE, None, None, filename, 
    209                 track_num, 
    210                 title, 
    211                 artist, 
    212                 album, 
    213                 mesk.utils.format_track_time(src.audio_info.time_secs), 
    214                 year, 
     216        row_data[MODEL_NUM] = track_num 
     217 
     218        duration = mesk.utils.format_track_time(src.audio_info.time_secs) 
     219        row_data[MODEL_TIME] = duration 
     220         
     221        return row_data 
     222 
     223    def _new_model_row(self, src): 
     224        model_data = self._get_model_metadata(src) 
     225        return [MODEL_STATE_ACTIVE, None, None, src.uri.to_string(), 
     226                model_data[MODEL_NUM], 
     227                model_data[MODEL_TITLE], 
     228                model_data[MODEL_ARTIST], 
     229                model_data[MODEL_ALBUM], 
     230                model_data[MODEL_TIME], 
     231                model_data[MODEL_YEAR], 
    215232               ] 
    216233 
     
    369386        if src_index != len(self._playlist) - 1: 
    370387            gobject.idle_add(self._audio_control.next, True) 
     388 
     389    def _on_audio_tag_update(self, audio_control, audio_src): 
     390        row = self._playlist.index(audio_src) 
     391        model_iter = self._pl_model.get_iter(row) 
     392 
     393        model_data = self._get_model_metadata(audio_src) 
     394        for key in model_data: 
     395            self._pl_model.set_value(model_iter, key, model_data[key]) 
    371396 
    372397    def _on_dialog_close(self, dialog, response): 
  • trunk/src/plugins/audioscrobbler.py

    r257 r298  
    395395            src_len = audio_src.audio_info.time_secs 
    396396            if src_len < 30: 
    397                 self.log.info(_('Source length %d < 30s, skipping') % src_len) 
     397                self.log.info(_('Source length %s < 30s, skipping') % \ 
     398                              str(src_len)) 
    398399                return 
    399400            interval = min(src_len / 2, 240)