add bulk_run, thumbs, and initial sub_commands
[mediagoblin.git] / mediagoblin / gmg_commands / reprocess.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 import argparse
17 import os
18
19 from mediagoblin import mg_globals
20 from mediagoblin.db.models import MediaEntry
21 from mediagoblin.gmg_commands import util as commands_util
22 from mediagoblin.submit.lib import run_process_media
23 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
24 from mediagoblin.tools.pluginapi import hook_handle
25 from mediagoblin.processing import (
26 ProcessorDoesNotExist, ProcessorNotEligible,
27 get_entry_and_processing_manager, get_processing_manager_for_type)
28
29
30 def reprocess_parser_setup(subparser):
31 subparser.add_argument(
32 '--celery',
33 action='store_true',
34 help="Don't process eagerly, pass off to celery")
35
36 subparsers = subparser.add_subparsers(dest="reprocess_subcommand")
37
38 ###################
39 # available command
40 ###################
41 available_parser = subparsers.add_parser(
42 "available",
43 help="Find out what actions are available for this media")
44
45 available_parser.add_argument(
46 "id_or_type",
47 help="Media id or media type to check")
48
49 available_parser.add_argument(
50 "--action-help",
51 action="store_true",
52 help="List argument help for each action available")
53
54 available_parser.add_argument(
55 "--state",
56 help="The state of media you would like to reprocess")
57
58
59 #############
60 # run command
61 #############
62
63 run_parser = subparsers.add_parser(
64 "run",
65 help="Run a reprocessing on one or more media")
66
67 run_parser.add_argument(
68 'media_id',
69 help="The media_entry id(s) you wish to reprocess.")
70
71 run_parser.add_argument(
72 'reprocess_command',
73 help="The reprocess command you intend to run")
74
75 run_parser.add_argument(
76 'reprocess_args',
77 nargs=argparse.REMAINDER,
78 help="rest of arguments to the reprocessing tool")
79
80
81 ################
82 # thumbs command
83 ################
84 thumbs = subparsers.add_parser(
85 'thumbs',
86 help='Regenerate thumbs for all processed media')
87
88 thumbs.add_argument(
89 '--size',
90 nargs=2,
91 type=int,
92 metavar=('max_width', 'max_height'))
93
94 #################
95 # initial command
96 #################
97 subparsers.add_parser(
98 'initial',
99 help='Reprocess all failed media')
100
101 ##################
102 # bulk_run command
103 ##################
104 bulk_run_parser = subparsers.add_parser(
105 'bulk_run',
106 help='Run reprocessing on a given media type or state')
107
108 bulk_run_parser.add_argument(
109 'type',
110 help='The type of media you would like to process')
111
112 bulk_run_parser.add_argument(
113 'state',
114 default='processed',
115 help='The state of the media you would like to process. Defaults to' \
116 " 'processed'")
117
118 bulk_run_parser.add_argument(
119 'reprocess_args',
120 nargs=argparse.REMAINDER,
121 help='The rest of the arguments to the reprocessing tool')
122
123 ###############
124 # help command?
125 ###############
126
127
128
129 def _set_media_type(args):
130 """
131 This will verify that all media id's are of the same media_type. If the
132 --type flag is set, it will be replaced by the given media id's type.
133
134 If they are trying to process different media types, an Exception will be
135 raised.
136 """
137 if args[0].media_id:
138 if len(args[0].media_id) == 1:
139 args[0].type = MediaEntry.query.filter_by(id=args[0].media_id[0])\
140 .first().media_type.split('.')[-1]
141
142 elif len(args[0].media_id) > 1:
143 media_types = []
144
145 for id in args[0].media_id:
146 media_types.append(MediaEntry.query.filter_by(id=id).first()
147 .media_type.split('.')[-1])
148 for type in media_types:
149 if media_types[0] != type:
150 raise Exception((u'You cannot reprocess different'
151 ' media_types at the same time.'))
152
153 args[0].type = media_types[0]
154
155
156 def _reprocess_all(args):
157 """
158 This handles reprocessing if no media_id's are given.
159 """
160 if not args[0].type:
161 # If no media type is given, we can either regenerate all thumbnails,
162 # or try to reprocess all failed media
163
164 if args[0].thumbnails:
165 if args[0].available:
166 print _('Available options for regenerating all processed'
167 ' media thumbnails: \n'
168 '\t --size: max_width max_height'
169 ' (defaults to config specs)')
170 else:
171 #TODO regenerate all thumbnails
172 pass
173
174 # Reprocess all failed media
175 elif args[0].state == 'failed':
176 if args[0].available:
177 print _('\n Available reprocess actions for all failed'
178 ' media_entries: \n \t --initial_processing')
179 else:
180 #TODO reprocess all failed entries
181 pass
182
183 # If here, they didn't set the --type flag and were trying to do
184 # something other the generating thumbnails or initial_processing
185 else:
186 raise Exception(_('You must set --type when trying to reprocess'
187 ' all media_entries, unless you set --state'
188 ' to "failed".'))
189
190 else:
191 _run_reprocessing(args)
192
193
194 def _run_reprocessing(args):
195 # Are they just asking for the available reprocessing options for the given
196 # media?
197 if args[0].available:
198 if args[0].state == 'failed':
199 print _('\n Available reprocess actions for all failed'
200 ' media_entries: \n \t --initial_processing')
201 else:
202 result = hook_handle(('reprocess_action', args[0].type), args)
203 if not result:
204 print _('Sorry there is no available reprocessing for {}'
205 ' entries in the {} state'.format(args[0].type,
206 args[0].state))
207 else:
208 # Run media reprocessing
209 return hook_handle(('media_reprocess', args[0].type), args)
210
211
212 def _set_media_state(args):
213 """
214 This will verify that all media id's are in the same state. If the
215 --state flag is set, it will be replaced by the given media id's state.
216
217 If they are trying to process different media states, an Exception will be
218 raised.
219 """
220 if args[0].media_id:
221 # Only check if we are given media_ids
222 if len(args[0].media_id) == 1:
223 args[0].state = MediaEntry.query.filter_by(id=args[0].media_id[0])\
224 .first().state
225
226 elif len(args[0].media_id) > 1:
227 media_states = []
228
229 for id in args[0].media_id:
230 media_states.append(MediaEntry.query.filter_by(id=id).first()
231 .state)
232
233 # Make sure that all media are in the same state
234 for state in media_states:
235 if state != media_states[0]:
236 raise Exception(_('You can only reprocess media that is in'
237 ' the same state.'))
238
239 args[0].state = media_states[0]
240
241 # If no state was set, then we will default to the processed state
242 if not args[0].state:
243 args[0].state = 'processed'
244
245
246 def available(args):
247 # Get the media type, either by looking up media id, or by specific type
248 try:
249 media_id = int(args.id_or_type)
250 media_entry, manager = get_entry_and_processing_manager(media_id)
251 media_type = media_entry.media_type
252 except ValueError:
253 media_type = args.id_or_type
254 media_entry = None
255 manager = get_processing_manager_for_type(media_type)
256
257 if args.state:
258 processors = manager.list_all_processors_by_state(args.state)
259 elif media_entry is None:
260 processors = manager.list_all_processors()
261 else:
262 processors = manager.list_eligible_processors(media_entry)
263
264 print "Available processors:"
265 print "====================="
266 print ""
267
268 if args.action_help:
269 for processor in processors:
270 print processor.name
271 print "-" * len(processor.name)
272
273 parser = processor.generate_parser()
274 parser.print_help()
275 print ""
276
277 else:
278 for processor in processors:
279 if processor.description:
280 print " - %s: %s" % (processor.name, processor.description)
281 else:
282 print " - %s" % processor.name
283
284
285 def run(args):
286 media_entry, manager = get_entry_and_processing_manager(args.media_id)
287
288 # TODO: (maybe?) This could probably be handled entirely by the
289 # processor class...
290 try:
291 processor_class = manager.get_processor(
292 args.reprocess_command, media_entry)
293 except ProcessorDoesNotExist:
294 print 'No such processor "%s" for media with id "%s"' % (
295 args.reprocess_command, media_entry.id)
296 return
297 except ProcessorNotEligible:
298 print 'Processor "%s" exists but media "%s" is not eligible' % (
299 args.reprocess_command, media_entry.id)
300 return
301
302 reprocess_parser = processor_class.generate_parser()
303 reprocess_args = reprocess_parser.parse_args(args.reprocess_args)
304 reprocess_request = processor_class.args_to_request(reprocess_args)
305 run_process_media(
306 media_entry,
307 reprocess_action=args.reprocess_command,
308 reprocess_info=reprocess_request)
309
310 def bulk_run(args):
311 pass
312
313
314 def thumbs(args):
315 #TODO regenerate thumbs for all processed media
316 pass
317
318
319 def initial(args):
320 #TODO initial processing on all failed media
321 pass
322
323
324 def reprocess(args):
325 # Run eagerly unless explicetly set not to
326 if not args.celery:
327 os.environ['CELERY_ALWAYS_EAGER'] = 'true'
328
329 commands_util.setup_app(args)
330
331 if args.reprocess_subcommand == "run":
332 run(args)
333
334 elif args.reprocess_subcommand == "available":
335 available(args)
336
337 elif args.reprocess_subcommand == "bulk_run":
338 bulk_run(args)
339
340 elif args.reprocess_subcommand == "thumbs":
341 thumbs(args)
342
343 elif args.reprocess_subcommand == "initial":
344 initial(args)