Moved note handling commands to hooke.plugin.note.
[hooke.git] / hooke / plugin / playlist.py
1 """The `playlist` module provides :class:`PlaylistPlugin` several
2 associated :class:`hooke.command.Command`\s for handling
3 :mod:`hooke.playlist` classes.
4 """
5
6 import glob
7
8 from ..command import Command, Argument, Failure
9 from ..playlist import FilePlaylist
10 from ..plugin import Builtin
11
12
13 class PlaylistPlugin (Builtin):
14     def __init__(self):
15         super(PlaylistPlugin, self).__init__(name='playlist')
16
17     def commands(self):
18         return [NextCommand(), PreviousCommand(), JumpCommand(),
19                 SaveCommand(), LoadCommand(),
20                 AddCommand(), AddGlobCommand(),
21                 RemoveCommand(), FilterCommand(), NoteFilterCommand()]
22
23
24 # Define common or complicated arguments
25
26 def current_playlist_callback(hooke, command, argument, value):
27     if value != None:
28         return value
29     playlist = hooke.playlists.current()
30     if playlist == None:
31         raise Failure('No playlists loaded')
32     return playlist
33
34 PlaylistArgument = Argument(
35     name='playlist', type='playlist', callback=current_playlist_callback,
36     help="""
37 :class:`hooke.plugin.playlist.Playlist` to act on.  Defaults to the
38 current playlist.
39 """.strip())
40
41 def playlist_name_callback(hooke, command, argument, value):
42         return hooke.playlists.free_name()
43
44 PlaylistNameArgument = Argument(
45     name='name', type='string', optional=True, callback=playlist_name_callback,
46     help="""
47 Name of the new playlist (defaults to an auto-generated name).
48 """.strip())
49
50
51 # Define commands
52
53 class NextCommand (Command):
54     """Move playlist to the next curve.
55     """
56     def __init__(self):
57         super(NextCommand, self).__init__(
58             name='next curve',
59             arguments=[PlaylistArgument],
60             help=self.__doc__)
61
62     def _run(self, hooke, inqueue, outqueue, params):
63         params['playlist'].next()
64
65 class PreviousCommand (Command):
66     """Move playlist to the previous curve.
67     """
68     def __init__(self):
69         super(PreviousCommand, self).__init__(
70             name='previous curve',
71             arguments=[PlaylistArgument],
72             help=self.__doc__)
73
74     def _run(self, hooke, inqueue, outqueue, params):
75         params['playlist'].previous()
76
77 class JumpCommand (Command):
78     """Move playlist to a given curve.
79     """
80     def __init__(self):
81         super(JumpCommand, self).__init__(
82             name='jump to curve',
83             arguments=[
84                 PlaylistArgument,
85                 Argument(name='index', type='int', optional=False, help="""
86 Index of target curve.
87 """.strip()),
88                 ],
89             help=self.__doc__)
90
91     def _run(self, hooke, inqueue, outqueue, params):
92         params['playlist'].jump(params['index'])
93
94 class SaveCommand (Command):
95     """Save a playlist.
96     """
97     def __init__(self):
98         super(SaveCommand, self).__init__(
99             name='save playlist',
100             arguments=[
101                 PlaylistArgument,
102                 Argument(name='output', type='file',
103                          help="""
104 File name for the output playlist.  Defaults to overwriting the input
105 playlist.
106 """.strip()),
107                 ],
108             help=self.__doc__)
109
110     def _run(self, hooke, inqueue, outqueue, params):
111         params['playlist'].save(params['output'])
112
113 class LoadCommand (Command):
114     """Load a playlist.
115     """
116     def __init__(self):
117         super(LoadCommand, self).__init__(
118             name='load playlist',
119             arguments=[
120                 Argument(name='input', type='file', optional=False,
121                          help="""
122 File name for the input playlist.
123 """.strip()),
124                 Argument(name='drivers', type='driver', optional=False,
125                          count=-1,
126                          help="""
127 Drivers for loading curves.
128 """.strip()),
129                 ],
130             help=self.__doc__)
131
132     def _run(self, hooke, inqueue, outqueue, params):
133         p = FilePlaylist(drivers=params['drivers'], path=params['input'])
134         p.load()
135         hooke.playlists.append(p)
136         outqueue.put(p)
137
138 class AddCommand (Command):
139     """Add a curve to a playlist.
140     """
141     def __init__(self):
142         super(AddCommand, self).__init__(
143             name='add curve to playlist',
144             arguments=[
145                 PlaylistArgument,
146                 Argument(name='input', type='file', optional=False,
147                          help="""
148 File name for the input :class:`hooke.curve.Curve`.
149 """.strip()),
150                 Argument(name='info', type='dict', optional=True,
151                          help="""
152 Additional information for the input :class:`hooke.curve.Curve`.
153 """.strip()),
154                 ],
155             help=self.__doc__)
156
157     def _run(self, hooke, inqueue, outqueue, params):
158         params['playlist'].append_curve_by_path(params['input'],
159                                                 params['info'])
160
161 class AddGlobCommand (Command):
162     """Add curves to a playlist with file globbing.
163
164     Adding lots of files one at a time can be tedious.  With this
165     command you can use globs (`data/curves/*.dat`) to add curves
166     for all matching files at once.
167     """
168     def __init__(self):
169         super(AddGlobCommand, self).__init__(
170             name='glob curves to playlist',
171             arguments=[
172                 PlaylistArgument,
173                 Argument(name='input', type='glob', optional=False,
174                          help="""
175 File name glob for the input :class:`hooke.curve.Curve`.
176 """.strip()),
177                 Argument(name='info', type='dict', optional=True,
178                          help="""
179 Additional information for the input :class:`hooke.curve.Curve`.
180 """.strip()),
181                 ],
182             help=self.__doc__)
183
184     def _run(self, hooke, inqueue, outqueue, params):
185         for path in sorted(glob.glob(params['input'])):
186             params['playlist'].append_curve_by_path(path, params['info'])
187
188 class RemoveCommand (Command):
189     """Remove a curve from a playlist.
190     """
191     def __init__(self):
192         super(RemoveCommand, self).__init__(
193             name='remove curve from playlist',
194             arguments=[
195                 PlaylistArgument,
196                 Argument(name='index', type='int', optional=False, help="""
197 Index of target curve.
198 """.strip()),
199                 ],
200             help=self.__doc__)
201
202     def _run(self, hooke, inqueue, outqueue, params):
203         params['playlist'].pop(params['index'])
204         params['playlist'].jump(params._index)
205
206 class FilterCommand (Command):
207     """Create a subset playlist via a selection function.
208
209     Removing lots of curves one at a time can be tedious.  With this
210     command you can use a function `filter` to select the curves you
211     wish to keep.
212     """
213     def __init__(self):
214         super(FilterCommand, self).__init__(
215             name='filter playlist',
216             arguments=[
217                 PlaylistArgument,
218                 PlaylistNameArgument,
219                 Argument(name='filter', type='function', optional=False,
220                          help="""
221 Function returning `True` for "good" curves.  `filter(curve) -> True/False`.
222 """.strip()),
223                 ],
224             help=self.__doc__)
225
226     def _run(self, hooke, inqueue, outqueue, params):
227         p = params['playlist'].filter(params['filter'])
228         hooke.playlists.add(p)
229         outqueue.put(p)
230
231 class NoteFilterCommand (FilterCommand):
232     """Create a subset playlist of curves with `.info['note'] != None`.
233     """
234     def __init__(self):
235         super(NoteFilterCommand, self).__init__()
236         self.name = 'note filter playlist'
237         self.arguments = [a for a in self.arguments if a.name != 'filter']
238
239     def _run(self, hooke, inqueue, outqueue, params):
240         params['filter'] = lambda curve : \
241             'note' in curve.info and curve.info['note'] != None
242         return super(NoteFilterCommand, self)._run(
243             hooke, inqueue, outqueue, params)