/python/mp3mill/millconsole.py
Python | 312 lines | 267 code | 16 blank | 29 comment | 1 complexity | 0062e226f85f5b64e498bb2671b50172 MD5 | raw file
- """Top level module, interactive console application.
- Provides media files playback, bookmarking, fragments copying.
- MP3 format only is supported currently.
- """
- import cmd
- import os
- import os.path
- import readline
- from readline import *
- import sys
- import traceback
- import bookmarks
- import mill
- from mill import *
- import mill_aux
- from mill_aux import *
- import pymplayer
- # TODO:
- # - shell call should change process environment variables.
- # BUGS:
- # - loop always runs playback;
- # - sometimes no playback runs after file load.
- class MillConsole(cmd.Cmd):
- """Key class - shell.
-
- Supports player operations, bookmarks operations
- and fragment copy.
- """
-
- # Console prompt string by default
- DEFAULT_PROMPT = 'Mill->'
-
- def __init__(self, player, stream_prototype):
- """Constructor.
-
- Arguments:
- player - player background process wrapper
- (e.g. pymplayer.Player class instance);
- stream_prototype - prototype for media stream
- (e.g. mill.MP3DummyStream instance).
- """
- cmd.Cmd.__init__(self)
- self.__bookmarks = {}
- self.__stream_prototype = stream_prototype
- self.__player = player
- self.set_prompt()
-
- #--- Override inherited methods
-
- def emptyline(self):
- """Empty command handler.
-
- Override undesired inherited behaviour (last command call).
- """
- pass
-
- def precmd(self, cmdline):
- """'Before command executed' hook."""
- # These commands does not require file loaded.
- basic_commands = (
- '?', 'help', 'cd', 'ls', 'load', 'q', 'quit'
- )
-
- # cmdline is a string. Split it on different tokens,
- # result may be a list with command in a 1-st item, or
- # an empty list (if cmdline is an empty string).
- #
- # Command starting with '!' symbol s.b. redirected to
- # the OS shell.
- cmdlist = cmdline.split()
-
- if not (
- (not cmdlist) or
- (cmdlist[0] in basic_commands) or
- (cmdlist[0].startswith('!')) or
- (self.__player.get_file_name())
- ):
- print 'No file was loaded, call "load" command at first.'
- return 'help load'
- else:
- return cmdline
-
- def onecmd(self, cmdline):
- """Custom command handler.
-
- Is overriden to catch possible exceptions.
- """
- try:
- return cmd.Cmd.onecmd(self, cmdline)
- except ValueError, e:
- print 'error occured: %s'% (e,)
- except:
- sep_bar = '*' * 72
- print sep_bar
- print 'SERIOUS ERROR OCCURED: \n'
- traceback.print_exc(file=sys.stdout)
- print sep_bar
-
- def postcmd(self, stop, cmdline):
- """'After command executed' hook."""
- self.set_prompt()
- return stop
-
- def set_prompt(self):
- """Set command line prompt."""
- filename = self.__player.get_file_name()
- if filename:
- self.prompt = os.path.basename(filename) + '>'
- else:
- self.prompt = self.DEFAULT_PROMPT
-
- #--- Specific methods
-
- def save_current_bookmarks(self):
- """Save current bookmarks to a file.
-
- Is called before load new media file or before exit.
- """
- bookmarks.bmdump(
- self.__bookmarks,
- bookmarks.bmfname(self.__player.get_file_name())
- )
-
- #--- Command handlers
-
- def do_q(self, args):
- """
- q -- quit from program.
- """
- return self.do_quit(args)
-
- def do_quit(self, args):
- """
- quit -- quit from program.
- """
- self.save_current_bookmarks()
- self.__player.quit()
- return True
-
- def do_shell(self, args):
- """
- shell -- execute command in system shell;
- NB! shell state (e.g. working directory) would be lost
- after shell execution completed.
- """
- os.system(args)
-
- def do_seek(self, args):
- """
- seek <[[hh:]mm:]ss> -- seek the position specified in hms string;
- seek <(+|-)[[hh:]mm:]ss> -- seek forwards/backwards by time
- specified in hms string;
- seek <val%> -- seek the position specified in percents of media
- file total duration;
- seek <bookmark> -- seek the position specified by bookmark (
- given by name either by bookmark number, number s.b.
- prefixed by '#' symbol
- ).
- """
- args = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
- self.__player.seek(
- *(pymplayer.str2seek(self.__bookmarks.get(args, args)))
- )
-
- def do_pause(self, args):
- """
- pause -- toggle pause/play.
- """
- self.__player.pause()
-
- def do_cd(self, args):
- """
- cd <dirname> -- change directory to the <dirname>.
- """
- os.chdir(args)
-
- def do_ls(self, args):
- """
- ls [<dirname>] -- list the directory content
- (list current work directory if dirname is omitted).
- """
- dirname = args.strip()
- if not dirname:
- dirname = os.getcwd()
- items = sorted(os.listdir(dirname))
- for item in items:
- print item
-
- def do_load(self, args):
- """
- load <filename> -- load media file specified.
- """
- if os.path.isfile(args):
- self.save_current_bookmarks()
- self.__player.loadfile(args)
- bookmarks.bmload(
- self.__bookmarks,
- bookmarks.bmfname(self.__player.get_file_name())
- )
- else:
- raise ValueError(
- "File '%s' not present or not a file" % (args,)
- )
-
- def do_loop(self, args):
- """
- loop -- go into player status display loop.
- """
- self.__player.loop()
-
- def do_now(self, args):
- """
- now -- print playing time position in seconds.
- """
- print sec2hms(
- self.__player.get_time_pos(
- pausing_keep=True, attempts=3
- )
- )
-
- def do_badd(self, args):
- """
- badd <bookmark> [[hh:]mm:]ss -- add a bookmark
- to the specified position;
- badd [[hh:]mm:]ss -- add a bookmark with the same
- name as a position.
- """
- bookmarks.bmadd(
- self.__bookmarks,
- lambda v: sec2hms(hms2sec(v)),
- *args.split()
- )
-
- def do_blist(self, args):
- """
- blist -- list current file bookmarks.
- """
- print bookmarks.bmstr(self.__bookmarks, hms2sec)
-
- def do_bdel(self, args):
- """
- bdel <bookmark> -- remove a bookmark given by name either by number
- (number s.b. prefixed by '#' symbol).
- """
- args = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
- del self.__bookmarks[args]
-
- def do_mill(self, args):
- """
- mill <name or position> -- save a fragment of the currently loaded
- file from the start timepoint to the end timepoint;
- the start timepoint and output file name (extension is the same,
- as for the currently loaded file)
- are obtained from the bookmark name or bookmark position
- (in [[[hh:]mm:]ss] format), or by bookmark number in bookmarks
- list (number s.b. prefixed by '#' symbol),
- and the end timepoint is the next bookmark after start timepoint.
- """
- strt = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
- fragment_name = strt + (os.path.splitext(
- self.__player.get_file_name()
- )[1]).lower()
- end = bookmarks.bmnext(
- strt, self.__bookmarks,
- hms2sec
- )
- bitrate = self.__player.get_audio_bitrate()
- if not end:
- raise ValueError(
- "Can't mill: no bookmark was found after %s" %
- (strt, )
- )
-
- print "Mill from %s to %s to file '%s', bitrate %s" % (
- strt, end, fragment_name, bitrate
- )
-
- self.__stream_prototype.bitrate = \
- bitrate
- filecopy(
- self.__player.get_file_name(), fragment_name,
- strt, end,
- self.__stream_prototype,
- self.__bookmarks
- )
- #======================================================================
- # APPLICATION ENTRY POINT
- #======================================================================
- def main():
- prototype = MP3DummyStream(None, None)
- app = MillConsole(pymplayer.Player(), prototype)
- app.cmdloop()
- if __name__ == "__main__":
- main()