PageRenderTime 41ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/python/mp3mill/millconsole.py

http://tinycode.googlecode.com/
Python | 312 lines | 267 code | 16 blank | 29 comment | 1 complexity | 0062e226f85f5b64e498bb2671b50172 MD5 | raw file
  1. """Top level module, interactive console application.
  2. Provides media files playback, bookmarking, fragments copying.
  3. MP3 format only is supported currently.
  4. """
  5. import cmd
  6. import os
  7. import os.path
  8. import readline
  9. from readline import *
  10. import sys
  11. import traceback
  12. import bookmarks
  13. import mill
  14. from mill import *
  15. import mill_aux
  16. from mill_aux import *
  17. import pymplayer
  18. # TODO:
  19. # - shell call should change process environment variables.
  20. # BUGS:
  21. # - loop always runs playback;
  22. # - sometimes no playback runs after file load.
  23. class MillConsole(cmd.Cmd):
  24. """Key class - shell.
  25. Supports player operations, bookmarks operations
  26. and fragment copy.
  27. """
  28. # Console prompt string by default
  29. DEFAULT_PROMPT = 'Mill->'
  30. def __init__(self, player, stream_prototype):
  31. """Constructor.
  32. Arguments:
  33. player - player background process wrapper
  34. (e.g. pymplayer.Player class instance);
  35. stream_prototype - prototype for media stream
  36. (e.g. mill.MP3DummyStream instance).
  37. """
  38. cmd.Cmd.__init__(self)
  39. self.__bookmarks = {}
  40. self.__stream_prototype = stream_prototype
  41. self.__player = player
  42. self.set_prompt()
  43. #--- Override inherited methods
  44. def emptyline(self):
  45. """Empty command handler.
  46. Override undesired inherited behaviour (last command call).
  47. """
  48. pass
  49. def precmd(self, cmdline):
  50. """'Before command executed' hook."""
  51. # These commands does not require file loaded.
  52. basic_commands = (
  53. '?', 'help', 'cd', 'ls', 'load', 'q', 'quit'
  54. )
  55. # cmdline is a string. Split it on different tokens,
  56. # result may be a list with command in a 1-st item, or
  57. # an empty list (if cmdline is an empty string).
  58. #
  59. # Command starting with '!' symbol s.b. redirected to
  60. # the OS shell.
  61. cmdlist = cmdline.split()
  62. if not (
  63. (not cmdlist) or
  64. (cmdlist[0] in basic_commands) or
  65. (cmdlist[0].startswith('!')) or
  66. (self.__player.get_file_name())
  67. ):
  68. print 'No file was loaded, call "load" command at first.'
  69. return 'help load'
  70. else:
  71. return cmdline
  72. def onecmd(self, cmdline):
  73. """Custom command handler.
  74. Is overriden to catch possible exceptions.
  75. """
  76. try:
  77. return cmd.Cmd.onecmd(self, cmdline)
  78. except ValueError, e:
  79. print 'error occured: %s'% (e,)
  80. except:
  81. sep_bar = '*' * 72
  82. print sep_bar
  83. print 'SERIOUS ERROR OCCURED: \n'
  84. traceback.print_exc(file=sys.stdout)
  85. print sep_bar
  86. def postcmd(self, stop, cmdline):
  87. """'After command executed' hook."""
  88. self.set_prompt()
  89. return stop
  90. def set_prompt(self):
  91. """Set command line prompt."""
  92. filename = self.__player.get_file_name()
  93. if filename:
  94. self.prompt = os.path.basename(filename) + '>'
  95. else:
  96. self.prompt = self.DEFAULT_PROMPT
  97. #--- Specific methods
  98. def save_current_bookmarks(self):
  99. """Save current bookmarks to a file.
  100. Is called before load new media file or before exit.
  101. """
  102. bookmarks.bmdump(
  103. self.__bookmarks,
  104. bookmarks.bmfname(self.__player.get_file_name())
  105. )
  106. #--- Command handlers
  107. def do_q(self, args):
  108. """
  109. q -- quit from program.
  110. """
  111. return self.do_quit(args)
  112. def do_quit(self, args):
  113. """
  114. quit -- quit from program.
  115. """
  116. self.save_current_bookmarks()
  117. self.__player.quit()
  118. return True
  119. def do_shell(self, args):
  120. """
  121. shell -- execute command in system shell;
  122. NB! shell state (e.g. working directory) would be lost
  123. after shell execution completed.
  124. """
  125. os.system(args)
  126. def do_seek(self, args):
  127. """
  128. seek <[[hh:]mm:]ss> -- seek the position specified in hms string;
  129. seek <(+|-)[[hh:]mm:]ss> -- seek forwards/backwards by time
  130. specified in hms string;
  131. seek <val%> -- seek the position specified in percents of media
  132. file total duration;
  133. seek <bookmark> -- seek the position specified by bookmark (
  134. given by name either by bookmark number, number s.b.
  135. prefixed by '#' symbol
  136. ).
  137. """
  138. args = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
  139. self.__player.seek(
  140. *(pymplayer.str2seek(self.__bookmarks.get(args, args)))
  141. )
  142. def do_pause(self, args):
  143. """
  144. pause -- toggle pause/play.
  145. """
  146. self.__player.pause()
  147. def do_cd(self, args):
  148. """
  149. cd <dirname> -- change directory to the <dirname>.
  150. """
  151. os.chdir(args)
  152. def do_ls(self, args):
  153. """
  154. ls [<dirname>] -- list the directory content
  155. (list current work directory if dirname is omitted).
  156. """
  157. dirname = args.strip()
  158. if not dirname:
  159. dirname = os.getcwd()
  160. items = sorted(os.listdir(dirname))
  161. for item in items:
  162. print item
  163. def do_load(self, args):
  164. """
  165. load <filename> -- load media file specified.
  166. """
  167. if os.path.isfile(args):
  168. self.save_current_bookmarks()
  169. self.__player.loadfile(args)
  170. bookmarks.bmload(
  171. self.__bookmarks,
  172. bookmarks.bmfname(self.__player.get_file_name())
  173. )
  174. else:
  175. raise ValueError(
  176. "File '%s' not present or not a file" % (args,)
  177. )
  178. def do_loop(self, args):
  179. """
  180. loop -- go into player status display loop.
  181. """
  182. self.__player.loop()
  183. def do_now(self, args):
  184. """
  185. now -- print playing time position in seconds.
  186. """
  187. print sec2hms(
  188. self.__player.get_time_pos(
  189. pausing_keep=True, attempts=3
  190. )
  191. )
  192. def do_badd(self, args):
  193. """
  194. badd <bookmark> [[hh:]mm:]ss -- add a bookmark
  195. to the specified position;
  196. badd [[hh:]mm:]ss -- add a bookmark with the same
  197. name as a position.
  198. """
  199. bookmarks.bmadd(
  200. self.__bookmarks,
  201. lambda v: sec2hms(hms2sec(v)),
  202. *args.split()
  203. )
  204. def do_blist(self, args):
  205. """
  206. blist -- list current file bookmarks.
  207. """
  208. print bookmarks.bmstr(self.__bookmarks, hms2sec)
  209. def do_bdel(self, args):
  210. """
  211. bdel <bookmark> -- remove a bookmark given by name either by number
  212. (number s.b. prefixed by '#' symbol).
  213. """
  214. args = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
  215. del self.__bookmarks[args]
  216. def do_mill(self, args):
  217. """
  218. mill <name or position> -- save a fragment of the currently loaded
  219. file from the start timepoint to the end timepoint;
  220. the start timepoint and output file name (extension is the same,
  221. as for the currently loaded file)
  222. are obtained from the bookmark name or bookmark position
  223. (in [[[hh:]mm:]ss] format), or by bookmark number in bookmarks
  224. list (number s.b. prefixed by '#' symbol),
  225. and the end timepoint is the next bookmark after start timepoint.
  226. """
  227. strt = bookmarks.bmbynumber(self.__bookmarks, hms2sec, args)
  228. fragment_name = strt + (os.path.splitext(
  229. self.__player.get_file_name()
  230. )[1]).lower()
  231. end = bookmarks.bmnext(
  232. strt, self.__bookmarks,
  233. hms2sec
  234. )
  235. bitrate = self.__player.get_audio_bitrate()
  236. if not end:
  237. raise ValueError(
  238. "Can't mill: no bookmark was found after %s" %
  239. (strt, )
  240. )
  241. print "Mill from %s to %s to file '%s', bitrate %s" % (
  242. strt, end, fragment_name, bitrate
  243. )
  244. self.__stream_prototype.bitrate = \
  245. bitrate
  246. filecopy(
  247. self.__player.get_file_name(), fragment_name,
  248. strt, end,
  249. self.__stream_prototype,
  250. self.__bookmarks
  251. )
  252. #======================================================================
  253. # APPLICATION ENTRY POINT
  254. #======================================================================
  255. def main():
  256. prototype = MP3DummyStream(None, None)
  257. app = MillConsole(pymplayer.Player(), prototype)
  258. app.cmdloop()
  259. if __name__ == "__main__":
  260. main()