import subprocess, dirutil, grp, mailbox, method, mode, os.path, pwd, re, sys import buffer, default, util, window from mode.mutt import MuttGrammar from lex import Grammar, PatternRule, RegionRule from point import Point from buffer import Buffer from method import Method, Argument, arg from method.shell import Interact try: import eyeD3 has_eyed3 = True except ImportError: has_eyed3 = False def _size_info(i): if i >= 1024 ** 2: return '%.2f MB' % (i * 1.0 / 1024 ** 2) elif i >= 1024: return '%.2f KB' % (i * 1.0 / 1024) else: return '%d B' % i def _time_info(i): if i >= 60 ** 2: (j, k) = (i // 60 ** 2, i % 60 ** 2) return '%d:%02d:%02d secs' % (j, k // 60, k % 60) elif i >= 60: return '%d:%02d secs' % (i // 60, i % 60) else: return '%d secs' % i def _str_info(s): if s: return str(s) else: return '' def _num_pair_info(t): if t[0] and t[1]: return '%s/%s' % t elif t[0]: return str(t[0]) elif t[1]: return '/%s' % t[1] else: return '' class Mp3Buffer(Buffer): btype = 'mp3' def __init__(self, path): Buffer.__init__(self) self.path = util.expand_tilde(path) self.base = os.path.basename(self.path) self.af = eyeD3.tag.Mp3AudioFile(self.path) self.tag = self.af.getTag() def changed(self): return False def readonly(self): return True def path_exists(self): raise Exception def _make_path(self, name): raise Exception def save(self, force=False): raise Exception("can't save an mbox") def save_as(self, path): raise Exception("can't save an mbox") def name(self): return 'mp3:%s' % (self.base) def open(self): self.lines = self._get_lines() def reload(self): self.set_lines(self._get_lines(), force=True) def _get_lines(self): lines = [ '# INFO', 'Filename: ' + os.path.basename(self.af.fileName), 'Filesize: ' + _size_info(self.af.fileSize), 'Playtime: ' + _time_info(self.af.getPlayTime()), 'Bitrate: ' + _str_info(self.af.getBitRate()), 'Samplerate: ' + _str_info(self.af.getSampleFreq()) + ' kHz', '# ID3', 'Artist: ' + _str_info(self.tag.getArtist()), 'Album: ' + _str_info(self.tag.getAlbum()), 'BPM: ' + _str_info(self.tag.getBPM()), #'CDID: ' + str(self.tag.getCDID()), #xyz 'Comment: ' + _str_info(self.tag.getComment()), 'DiscNum: ' + _num_pair_info(self.tag.getDiscNum()), 'Genre: ' + _str_info(self.tag.getGenre()), 'Publisher: ' + _str_info(self.tag.getPublisher()), 'Title: ' + _str_info(self.tag.getTitle()), 'TrackNum: ' + _num_pair_info(self.tag.getTrackNum()), #'Version: ' + _str_info(self.tag.getVersion()), 'Year: ' + _str_info(self.tag.getYear()), ] return lines class TagGrammar(Grammar): rules = [ PatternRule(r'data', r'[^\\\n]+'), PatternRule(r'escaped', r'\\x[0-9a-fA-F]{2}'), ] class Mp3Grammar(Grammar): rules = [ PatternRule(r'comment', r'#.*\n$'), PatternRule(r'mp3_label', r'^[^:]+(?=: )'), RegionRule(r'mp3_tag', r': ', TagGrammar, r'\n$'), ] class Mp3Refresh(Method): def _execute(self, w, **vargs): w.buffer.reload() class Mp3Play(Method): def _execute(self, w, **vargs): pass class Mpg123Play(Interact): args = [] def _execute(self, w, **vargs): path = os.path.realpath(w.buffer.path) Interact._execute(self, w, bname='*Mpg123*', cmd='mpg123 %r' % path) class Mp3OpenPath(Method): args = [arg('mp3', dt="path", p="Open MP3: ", dv=default.path_dirname, ld=True, h="mp3 to open")] def _execute(self, w, **vargs): b = Mp3Buffer(vargs['mp3']) b.open() window.Window(b, w.application, height=0, width=0, mode_name='mp3') w.application.add_buffer(b) w.application.switch_buffer(b) class Mp3(mode.Fundamental): name = 'Mp3' grammar = Mp3Grammar actions = [Mp3Refresh, Mp3OpenPath] colors = { 'mp3_label': ('blue', 'default', 'bold'), 'mp3_tag.start': ('default', 'default', 'bold'), 'mp3_tag.data': ('green', 'default', 'bold'), 'mp3_tag.escaped': ('magenta', 'default', 'bold'), } def __init__(self, w): mode.Fundamental.__init__(self, w) self.add_bindings('mp3-refresh', ('C-c r',)) if has_eyed3: install = Mp3.install else: install = lambda *args: None