def __init__(self, meta, subscriber, batchIndexAtStart=True): self.meta = meta self.subscriber = subscriber self.queueMode = batchIndexAtStart queryClass = getClassByName(self.meta['queryType']) self.queryManager = queryClass(self.meta) valueClass = getClassByName(self.meta['valueType']) self.valueManager = valueClass(self.meta, self.queryManager) self.valueCode = self.meta['valueCode'] self.cacheDir = os.path.join(DATA_PATH, 'plot', 'cache', self.valueCode) self.segmentDir = os.path.join(DATA_PATH, 'plot', self.valueCode) self.delayBox = DelayBox(self.writeOutputSegment, maxDelaySeconds=5, numBuckets=10) self.queue = deque() self.running = False self.status = None self.statusPath = None self.statusStore = None self.store = None self.batchProcessStartTime = None
def __init__(self, meta, subscriber, batchIndexAtStart=True): self.meta = meta self.subscriber = subscriber self.queueMode = batchIndexAtStart queryClass = getClassByName(self.meta['queryType']) self.queryManager = queryClass(self.meta) valueClass = getClassByName(self.meta['valueType']) self.valueManager = valueClass(self.meta, self.queryManager) self.valueCode = self.meta['valueCode'] self.cacheDir = os.path.join(DATA_PATH, 'plot', 'cache', self.valueCode) self.segmentDir = os.path.join(DATA_PATH, 'plot', self.valueCode) self.delayBox = DelayBox(self.writeOutputSegment, maxDelaySeconds=5, numBuckets=10) self.queue = deque() self.running = False self.status = None self.statusPath = None self.statusStore = None self.store = None self.batchProcessStartTime = None
def __init__(self, meta, parent, batchIndexAtStart=True): self.meta = meta self.parent = parent self.queueMode = batchIndexAtStart self.rgba = numpy.zeros((N, N, 4), dtype='uint8') queryClass = getClassByName(self.meta['queryType']) self.queryManager = queryClass(self.meta) self.valueClass = getClassByName(self.meta['valueType']) self.valueManager = self.valueClass(self.meta, self.queryManager) self.valueCode = self.meta['valueCode'] self.outputDir = os.path.join(DATA_PATH, self.valueCode) self.colorRange = self.meta['map']['colorRange'] colorBarPath = os.path.join(DATA_PATH, self.valueCode, 'colorbar.png') self.writeColorBar(colorBarPath) self.queue = deque() self.running = False self.status = None self.statusPath = None self.statusStore = None self.poseCollector = None self.batchProcessStartTime = None
def __init__(self, meta, parent, batchIndexAtStart=True): self.meta = meta self.parent = parent self.queueMode = batchIndexAtStart self.rgba = numpy.zeros((N, N, 4), dtype='uint8') queryClass = getClassByName(self.meta['queryType']) self.queryManager = queryClass(self.meta) self.valueClass = getClassByName(self.meta['valueType']) self.valueManager = self.valueClass(self.meta, self.queryManager) self.valueCode = self.meta['valueCode'] self.outputDir = os.path.join(DATA_PATH, self.valueCode) self.colorRange = self.meta['map']['colorRange'] colorBarPath = os.path.join(DATA_PATH, self.valueCode, 'colorbar.png') self.writeColorBar(colorBarPath) self.queue = deque() self.running = False self.status = None self.statusPath = None self.statusStore = None self.poseCollector = None self.batchProcessStartTime = None
def writePlotData(out, seriesId, widthPix=None, heightPix=None, minTime=None, maxTime=None): if widthPix is None: widthPix = 800 if heightPix is None: heightPix = 120 xinch = float(widthPix) / 100 yinch = float(heightPix) / 100 fig = plt.figure() meta = TIME_SERIES_LOOKUP[seriesId] queryClass = getClassByName(meta['queryType']) queryManager = queryClass(meta) valueClass = getClassByName(meta['valueType']) valueManager = valueClass(meta, queryManager) recs = queryManager.getData(minTime=minTime, maxTime=maxTime) timestamps = [epochMsToMatPlotLib(queryManager.getTimestamp(rec)) for rec in recs] vals = [valueManager.getValue(rec) for rec in recs] plt.plot(timestamps, vals) ax = fig.gca() ax.grid(True) xmin, xmax, ymin, ymax = ax.axis() if minTime: xmin = epochMsToMatPlotLib(minTime) if maxTime: xmax = epochMsToMatPlotLib(maxTime) if ymin == 0 and ymax == 1: # HACK styling special case ymin = -0.1 ymax = 1.1 ax.axis([xmin, xmax, ymin, ymax]) pylabUtil.setXAxisDate() plt.title(queryManager.getValueName(meta['valueField'])) logging.info('writePlotData: writing image') plt.setp(fig, figwidth=xinch, figheight=yinch) fig.savefig(out, format='png', bbox_inches='tight', dpi=100, pad_inches=0.05, # transparent=True, ) logging.info('writePlotData: releasing memory') fig.clf() plt.close(fig)
def getEpisodeSegmentsJson(request, flightName=None, sourceShortName=None): """ flightName is either flightName or groupFlightName Returns first segment of all sources that are part of a given episode. Used for both playing back videos from active episode and also for playing videos associated with each note. """ try: episode = None if flightName: episode = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME)(flightName) else: episode = getClassByName(settings.XGDS_VIDEO_GET_ACTIVE_EPISODE)() if not episode: raise Exception('no episode') except: return HttpResponse(json.dumps({'error': 'No episode found'}), content_type='application/json', status=406) active = episode.endTime is None if not flightName: flightName = episode.shortName # get the segments segments = {} if sourceShortName: segments[sourceShortName] = [ s.getDict() for s in episode.videosegment_set.filter( source__shortName=sourceShortName) ] else: distinctSources = episode.videosegment_set.values( 'source__shortName').distinct() for theSource in distinctSources: sn = str(theSource['source__shortName']) segments[sn] = [ s.getDict() for s in episode.videosegment_set.filter(source__shortName=sn) ] if not segments: return HttpResponse(json.dumps( {'error': 'No segments found for ' + flightName}), content_type='application/json', status=406) result = [] result.append({'active': active}) result.append({'episode': episode.getDict()}) result.append({'segments': segments}) return HttpResponse(json.dumps(result, sort_keys=True, indent=4, cls=DatetimeJsonEncoder), content_type='application/json')
def displayLiveVideo(request, sourceShortName=None): """ Directly display RTSP feeds for the active episode. This will either include all sources or be for a single source if it is passed in.. """ GET_ACTIVE_EPISODE_METHOD = getClassByName(settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) episode = GET_ACTIVE_EPISODE_METHOD() if not episode: messages.add_message(request, messages.ERROR, 'There is no live video.') return redirect(reverse('error')) sources = [] noteForms = [] if sourceShortName: try: source = SOURCE_MODEL.get().objects.get(shortName=str(sourceShortName)) sources.append(source) noteForms.append(buildNoteForm([episode], source, request, {'index':0})) except: pass else: # get sources and get feeds sources = SOURCE_MODEL.get().objects.filter(videosegment__episode = episode).distinct() for index,source in enumerate(sources): noteForms.append(buildNoteForm([episode], source, request, {'index':index})) noteModelName = str(NOTE_MODEL.get().cls_type()) noteForm = getClassByName(settings.XGDS_NOTES_BUILD_NOTES_FORM)({'vehicle__name':sourceShortName, 'flight__group_name':episode.shortName}) ctx = { 'episode': episode, 'isLive': True, 'zipped': zip(sources, noteForms), 'SSE': settings.XGDS_SSE, 'modelName': noteModelName, 'flightName': episode.shortName, 'flightTZ': settings.TIME_ZONE, 'searchModelDict': {noteModelName:settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]}, 'searchForms': {noteModelName: [noteForm,settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]] }, 'app': 'xgds_map_server/js/search/mapViewerSearchApp.js', 'templates': get_handlebars_templates(list(settings.XGDS_MAP_SERVER_HANDLEBARS_DIRS), 'XGDS_MAP_SERVER_HANDLEBARS_DIRS'), } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName(settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) theTemplate = 'xgds_video/map_live_playbacks.html' return render_to_response(theTemplate, ctx, context_instance=RequestContext(request))
def showStillViewerWindow(request, flightName=None, time=None): if flightName is None: return HttpResponse(json.dumps({ 'error': { 'code': -32199, 'message': 'You must provide params in URL, cheater.' } }), content_type='application/json') timestamp = datetime.datetime.strptime(time, "%Y-%m-%d_%H-%M-%S") event_timestring = timestamp.strftime("%Y-%m-%d %H:%M:%S") formattedTime = timestamp.strftime('%H:%M:%S') # build up the form try: flightGroup, videoSource = flightName.split("_") except: return recordedVideoError( request, "This flight cannot be made into modern stills " + flightName) GET_EPISODE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) source = SOURCE_MODEL.get().objects.get(shortName=videoSource) form = buildNoteForm([episode], source, request, {'index': 0}) # # form = NoteForm() # form.index = 0 # form.fields["index"] = 0 # form.source = source # form.fields["source"] = source # form.fields["extras"].initial = callGetNoteExtras([episode], form.source, request, form) stillLocationFxn = getClassByName(settings.XGDS_VIDEO_GPS_LOCATION_METHOD) locationInfo = stillLocationFxn(flightName, timestamp) return render( request, 'xgds_video/video_still_viewer.html', { 'form': form, 'flightName': flightName, 'source': source, 'position': locationInfo, 'formattedTime': formattedTime, 'timeKey': time, 'event_timestring': event_timestring }, )
def displayLiveVideo(request, sourceShortName=None): """ Directly display RTSP feeds for the active episode. This will either include all sources or be for a single source if it is passed in.. """ GET_ACTIVE_EPISODE_METHOD = getClassByName( settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) episode = GET_ACTIVE_EPISODE_METHOD() if not episode: messages.add_message(request, messages.ERROR, 'There is no live video.') return redirect(reverse('error')) sources = [] noteForms = [] if sourceShortName: try: source = SOURCE_MODEL.get().objects.get( shortName=str(sourceShortName)) sources.append(source) noteForms.append( buildNoteForm([episode], source, request, {'index': 0})) except: pass else: # get sources and get feeds sources = SOURCE_MODEL.get().objects.filter( videosegment__episode=episode).distinct() for index, source in enumerate(sources): noteForms.append( buildNoteForm([episode], source, request, {'index': index})) ctx = { 'episode': episode, 'zipped': zip(sources, noteForms), 'SSE': settings.XGDS_SSE } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName( settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) theTemplate = 'xgds_video/video_live_playbacks.html' return render_to_response(theTemplate, ctx, context_instance=RequestContext(request))
def grab_frame_from_time( grab_time, vehicle, author=None, prefix=settings.XGDS_IMAGE_FRAME_GRAB_FILENAME_PREFIX): """ Direct method to grab the frame given a time, without requests :param grab_time: the grab time datetime :param vehicle: the vehicle model :return: the ImageSet that was created """ flight = getFlight(grab_time, vehicle) if not flight: raise Exception("No flight for time %s" % str(grab_time)) # TODO we currently name episodes after group flights this may change. # Ideally have a link source = SOURCE_MODEL.get().objects.get(vehicle=vehicle) grab_info = prepare_grab_frame(flight.group.name, source.shortName, grab_time) # print('grab info is ') print(grab_info) if grab_info: SAVE_IMAGE_FUNCTION = getClassByName('xgds_image.views.do_grab_frame') # TODO we are assuming there is a camera named for the vehicle camera = CAMERA_MODEL.get().objects.get(name=vehicle.name) if not author: # TODO assuming there is a user named camera author = User.objects.get(username='******') return SAVE_IMAGE_FUNCTION(grab_info['segment'].startTime, grab_time, grab_info['file_path'], prefix, camera, author, vehicle, grab_info['index_file_path'])
def updateIndexFilePrefix(indexFileSuffix, subst, flightName): """ This is truncating the last n rows from the m3u8 file and reappending the end and the metadata at the top. This fakes our delay """ indexFilePath = settings.DATA_ROOT + indexFileSuffix segmentDirectoryUrl = settings.DATA_URL + os.path.dirname(indexFileSuffix) try: videoDelayInSecs = getClassByName(settings.XGDS_VIDEO_DELAY_AMOUNT_METHOD)(flightName) if videoDelayInSecs > 0: (videoDelayInSegments, m3u8_index) = getSegmentsFromEndForDelay(videoDelayInSecs-30, indexFilePath) else: m3u8_index = m3u8.load(indexFilePath) videoDelayInSegments = 0 segments = m3u8_index.segments if len(segments) > 0: if segments[0].duration > 100: del segments[0] if videoDelayInSegments > 0 and len(segments) > videoDelayInSegments: del segments[-videoDelayInSegments:] for s in segments: s.uri = str(segmentDirectoryUrl) + '/' + s.uri return m3u8_index.dumps() except: traceback.print_exc() traceback.print_stack() return segmentDirectoryUrl
def writeMapIndexKml(request, out): out.write(""" <Document> <name>Raster Maps</name> <open>1</open> """) getDatesFn = getClassByName(settings.XGDS_PLOT_GET_DATES_FUNCTION) dates = list(reversed(sorted(getDatesFn()))) nowTime = utcToTz(datetime.datetime.now(pytz.utc)) today = nowTime.date() if len(dates) >= 4 and dates[0] == today: # Put past days in a separate folder to avoid clutter. The user # is most likely to be interested in today's data. dates = [dates[0]] + ['pastDaysStart'] + dates[1:] + ['pastDaysEnd'] for day in dates: if day == 'pastDaysStart': out.write('<Folder><name>Past Days</name>\n') continue elif day == 'pastDaysEnd': out.write('</Folder>\n') continue isToday = (day == today) writeMapIndexKmlForDay(request, out, day, isToday) out.write(""" </Document> """)
def captureStillImage(flightName, timestamp): stillLocationFxn = getClassByName(settings.XGDS_VIDEO_GPS_LOCATION_METHOD) locationInfo = stillLocationFxn(flightName, timestamp) (chunkPath, offsetInChunk) = getChunkfilePathAndOffsetForTime(flightName, timestamp) captureParams = {'frameCaptureOffset': offsetInChunk, 'imageSubject': flightName, 'collectionTimeZoneName': settings.TIME_ZONE, 'outputDir': settings.IMAGE_CAPTURE_DIR, 'chunkFilePath': chunkPath, 'thumbnailSize': {'width': 100, 'height': 56.25}, 'contactInfo': 'http://www.pavilionlake.com', 'wallClockTime': calendar.timegm(timestamp.utctimetuple()), 'createThumbnail': True} if locationInfo: captureParams['locationInfo'] = {'latitude': locationInfo.latitude, 'longitude': locationInfo.longitude, 'altitude': locationInfo.depthMeters} # # Now, send request for still frame capture # context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect(settings.XGDS_VIDEO_STILL_GRAB_SERVICE) if chunkPath: # did we really find a video chunk? If so, grab frame socket.send(json.dumps(captureParams)) resp = json.loads(socket.recv()) else: resp = {'captureSuccess':False, 'imageUuid':None} if resp['captureSuccess']: logging.info("Image capture OK for %s at %s" % (flightName, timestamp)) else: logging.info("Image capture failed for %s at %s" % (flightName, timestamp))
def setSegmentEndTimes(segments, episode, source): """ If both the episode endtime and segments' endtimes are not available (we are live), set the segment end time as endTime value inferred from the index file Given dictionary of segments (key = source, value = segment). """ if not episode: print "CANNOT set segment end times for empty episode" + str(episode) return # for sourceShortName, segments in sourceSegmentsDict.iteritems(): flightName = episode.shortName + '_' + source.shortName # segments = sourceSegmentsDict[source.shortName] segments = sorted(segments, key=lambda segment: segment.segNumber) # if last segment has no endTime if (segments[-1].endTime is None) and (episode.endTime is None): segment = segments[-1] # last segment GET_INDEX_FILE_METHOD = getClassByName( settings.XGDS_VIDEO_INDEX_FILE_METHOD) suffix = GET_INDEX_FILE_METHOD(flightName, source.shortName, segment.segNumber) path = settings.DATA_ROOT + suffix segmentDuration = getTotalDuration(path) segment.endTime = segment.startTime + datetime.timedelta( seconds=segmentDuration) segment.save()
def handleCallbacks(request, plan, mode): for callback_mode, methodName, callback_type in settings.XGDS_PLANNER2_CALLBACK: if callback_mode==mode and callback_type==settings.PYTHON: foundMethod = getClassByName(methodName) if foundMethod: plan = foundMethod(request, plan) return plan
def handleCallbacks(request, plan, mode): for callback_mode, methodName, callback_type in settings.XGDS_PLANNER2_CALLBACK: if callback_mode==mode and callback_type==settings.PYTHON: foundMethod = getClassByName(methodName) if foundMethod: plan = foundMethod(request, plan) return plan
def writeMapIndexKml(request, out): out.write(""" <Document> <name>Raster Maps</name> <open>1</open> """) getDatesFn = getClassByName(settings.XGDS_PLOT_GET_DATES_FUNCTION) dates = list(reversed(sorted(getDatesFn()))) nowTime = utcToTz(datetime.datetime.now(pytz.utc)) today = nowTime.date() if len(dates) >= 4 and dates[0] == today: # Put past days in a separate folder to avoid clutter. The user # is most likely to be interested in today's data. dates = [dates[0]] + ['pastDaysStart'] + dates[1:] + ['pastDaysEnd'] for day in dates: if day == 'pastDaysStart': out.write('<Folder><name>Past Days</name>\n') continue elif day == 'pastDaysEnd': out.write('</Folder>\n') continue isToday = (day == today) writeMapIndexKmlForDay(request, out, day, isToday) out.write(""" </Document> """)
def updateIndexFilePrefix(indexFileSuffix, subst, flightName): """ This is truncating the last n rows from the m3u8 file and reappending the end and the metadata at the top. This fakes our delay """ indexFilePath = settings.DATA_ROOT + indexFileSuffix segmentDirectoryUrl = settings.DATA_URL + os.path.dirname(indexFileSuffix) try: videoDelayInSecs = getClassByName( settings.XGDS_VIDEO_DELAY_AMOUNT_METHOD)(flightName) if videoDelayInSecs > 0: (videoDelayInSegments, m3u8_index) = getSegmentsFromEndForDelay(videoDelayInSecs - 30, indexFilePath) else: m3u8_index = m3u8.load(indexFilePath) videoDelayInSegments = 0 segments = m3u8_index.segments if len(segments) > 0: if segments[0].duration > 100: del segments[0] if videoDelayInSegments > 0 and len( segments) > videoDelayInSegments: del segments[-videoDelayInSegments:] for s in segments: s.uri = str(segmentDirectoryUrl) + '/' + s.uri return m3u8_index.dumps() except: traceback.print_exc() traceback.print_stack() return segmentDirectoryUrl
def getSegmentForTime(flightName, time): try: flightGroup, videoSource = flightName.split("_") source = SOURCE_MODEL.get().objects.get(shortName=videoSource) except: return None GET_EPISODE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) if episode.endTime: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime__gte=time, source=source) return segment else: try: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime__gte=time, source=source) except: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime=None, source=source) return segment
def plan_editor_app(request, plan_id=None, editable=True): templates = get_handlebars_templates(settings.XGDS_PLANNER2_HANDLEBARS_DIRS, 'XGDS_PLANNER2_HANDLEBARS_DIRS') plan = PLAN_MODEL.get().objects.get(pk=plan_id) dirty = False if not plan.jsonPlan.serverId: plan.jsonPlan.serverId = plan.pk dirty = True if "None" in plan.jsonPlan.url: plan.jsonPlan.url = plan.get_absolute_url() dirty = True if dirty: plan.save() planSchema = models.getPlanSchema(plan.jsonPlan.platform.name) pe = None try: if plan.executions and plan.executions.count() > 0: pe = json.dumps(plan.executions.all()[0].toSimpleDict(), cls=DatetimeJsonEncoder) except: pass context = { 'templates': templates, 'app': 'xgds_planner2/js/plannerApp.js', 'saveSearchForm': MapSearchForm(), 'searchForms': getSearchForms(), 'flight_names': json.dumps(getAllFlightNames()), 'plan_schema_json': planSchema.getJsonSchema(), # xpjson.dumpDocumentToString(planSchema.getSchema()), 'plan_library_json': planSchema.getJsonLibrary(), # xpjson.dumpDocumentToString(planSchema.getLibrary()), 'plan_json': json.dumps(plan.jsonPlan), 'plan_name': plan.name, 'plan_execution': pe, 'plan_index_json': json.dumps(plan_index_json()), 'editable': editable and not plan.readOnly, 'simulatorUrl': planSchema.simulatorUrl, 'simulator': planSchema.simulator, 'placemark_circle_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_circle.png') ), 'placemark_circle_highlighted_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_circle_highlighted.png') ), 'placemark_directional_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_directional.png') ), 'placemark_selected_directional_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_directional_highlighted.png') ), 'plan_links_json': json.dumps(plan.getLinks()) } return render_to_response( 'xgds_planner2/planner_app.html', RequestContext(request, getClassByName(settings.XGDS_PLANNER2_EDITOR_CONTEXT_METHOD)(context)), )
def expandTimeSeriesMeta(meta): """ Evaluates IncludeMeta and IncludeFunctionResultMeta objects. Returns a list of trees with Group and TimeSeries nodes. """ mtype = meta["type"] if mtype == "Group": lists = [expandTimeSeriesMeta(m) for m in meta["members"]] return [{"type": "Group", "members": reduce(operator.add, lists, [])}] elif mtype == "TimeSeries": return [meta.copy()] elif mtype == "IncludeMeta": return [expandTimeSeriesMeta(m) for m in getClassByName(meta["name"])] elif mtype == "IncludeFunctionResultMeta": func = getClassByName(meta["name"]) return reduce(operator.add, [expandTimeSeriesMeta(m) for m in func()], []) else: raise ValueError("expandTimeSeriesMeta: unknown meta type %s" % mtype)
def plan_editor_app(request, plan_id=None, editable=True): templates = get_handlebars_templates(settings.XGDS_PLANNER2_HANDLEBARS_DIRS, 'XGDS_PLANNER2_HANDLEBARS_DIRS') plan = PLAN_MODEL.get().objects.get(pk=plan_id) dirty = False if not plan.jsonPlan.serverId: plan.jsonPlan.serverId = plan.pk dirty = True if "None" in plan.jsonPlan.url: plan.jsonPlan.url = plan.get_absolute_url() dirty = True if dirty: plan.save() planSchema = models.getPlanSchema(plan.jsonPlan.platform.name) pe = None try: if plan.executions and plan.executions.count() > 0: pe = json.dumps(plan.executions.all()[0].toSimpleDict(), cls=DatetimeJsonEncoder) except: pass context = { 'templates': templates, 'app': 'xgds_planner2/js/plannerApp.js', 'saveSearchForm': MapSearchForm(), 'searchForms': getSearchForms(), 'flight_names': json.dumps(getAllFlightNames()), 'plan_schema_json': planSchema.getJsonSchema(), # xpjson.dumpDocumentToString(planSchema.getSchema()), 'plan_library_json': planSchema.getJsonLibrary(), # xpjson.dumpDocumentToString(planSchema.getLibrary()), 'plan_json': json.dumps(plan.jsonPlan), 'plan_name': plan.name, 'plan_execution': pe, 'plan_index_json': json.dumps(plan_index_json()), 'editable': editable and not plan.readOnly, 'simulatorUrl': planSchema.simulatorUrl, 'simulator': planSchema.simulator, 'placemark_circle_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_circle.png') ), 'placemark_circle_highlighted_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_circle_highlighted.png') ), 'placemark_directional_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_directional.png') ), 'placemark_selected_directional_url': request.build_absolute_uri( staticfiles_storage.url('xgds_planner2/images/placemark_directional_highlighted.png') ), 'plan_links_json': json.dumps(plan.getLinks()) } return render(request, 'xgds_planner2/planner_app.html', getClassByName(settings.XGDS_PLANNER2_EDITOR_CONTEXT_METHOD)(context))
def setupTimeSeries(): """ Process the XGDS_PLOT_TIME_SERIES setting. Normalize and fill in default values as needed. """ if not settings.XGDS_PLOT_TIME_SERIES: return [] tree = expandTimeSeriesMeta(settings.XGDS_PLOT_TIME_SERIES)[0] metaList = flattenTimeSeriesMeta(tree) for series in metaList: series.setdefault("queryType", "xgds_plot.query.Django") series.setdefault("valueType", "xgds_plot.value.Scalar") queryClass = getClassByName(series["queryType"]) queryManager = queryClass(series) valueClass = getClassByName(series["valueType"]) _valueManager = valueClass(series, queryManager) return metaList
def showStillViewerWindow(request, flightName=None, time=None): if flightName is None: return HttpResponse(json.dumps({'error': {'code': -32199, 'message': 'You must provide params in URL, cheater.'} }), content_type='application/json') timestamp = datetime.datetime.strptime(time, "%Y-%m-%d_%H-%M-%S") event_timestring = timestamp.strftime("%Y-%m-%d %H:%M:%S") formattedTime = timestamp.strftime('%H:%M:%S') # build up the form try: flightGroup, videoSource = flightName.split("_") except: return recordedVideoError(request, "This flight cannot be made into modern stills " + flightName) GET_EPISODE_FROM_NAME_METHOD = getClassByName(settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) source = SOURCE_MODEL.get().objects.get(shortName=videoSource) form = buildNoteForm([episode], source, request, {'index':0}) # # form = NoteForm() # form.index = 0 # form.fields["index"] = 0 # form.source = source # form.fields["source"] = source # form.fields["extras"].initial = callGetNoteExtras([episode], form.source, request, form) stillLocationFxn = getClassByName(settings.XGDS_VIDEO_GPS_LOCATION_METHOD) locationInfo = stillLocationFxn(flightName, timestamp) return render_to_response('xgds_video/video_still_viewer.html', {'form': form, 'flightName': flightName, 'source': source, 'position': locationInfo, 'formattedTime': formattedTime, 'timeKey': time, 'event_timestring': event_timestring}, context_instance=RequestContext(request))
def getEpisodeSegmentsJson(request, flightName=None, sourceShortName=None): """ flightName is either flightName or groupFlightName Returns first segment of all sources that are part of a given episode. Used for both playing back videos from active episode and also for playing videos associated with each note. """ episode = None if flightName: episode = getClassByName(settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME)(flightName) else: episode = getClassByName(settings.XGDS_VIDEO_GET_ACTIVE_EPISODE)() if not episode: return HttpResponse(json.dumps({'error': 'No episode found'}), content_type='application/json', status=406) active = (episode.endTime == None) if not flightName: flightName = episode.shortName # get the segments segments = {} if sourceShortName: segments[sourceShortName] = [ s.getDict() for s in episode.videosegment_set.filter(source__shortName=sourceShortName)] else: distinctSources = episode.videosegment_set.values('source__shortName').distinct() for theSource in distinctSources: sn = str(theSource['source__shortName']) segments[sn] = [ s.getDict() for s in episode.videosegment_set.filter(source__shortName=sn)] if not segments: return HttpResponse(json.dumps({'error': 'No segments found for ' + flightName}), content_type='application/json', status=406) result = [] result.append({'active': active}) result.append({'episode': episode.getDict()}) result.append({'segments': segments }) return HttpResponse(json.dumps(result, sort_keys=True, indent=4, cls=DatetimeJsonEncoder), content_type='application/json')
def videoIndexFile(request, flightName=None, sourceShortName=None, segmentNumber=None): """ modifies index file of recorded video to the correct host. """ # Look up path to index file GET_INDEX_FILE_METHOD = getClassByName(settings.XGDS_VIDEO_INDEX_FILE_METHOD) suffix = GET_INDEX_FILE_METHOD(flightName, sourceShortName, segmentNumber) # use regex substitution to replace hostname, etc. newIndex = util.updateIndexFilePrefix(suffix, settings.SCRIPT_NAME, flightName) # return modified file in next line response = HttpResponse(newIndex, content_type="application/x-mpegurl") response['Content-Disposition'] = 'filename = "prog_index.m3u8"' return response
def planIndex(request): """ For the moment this is a handy classic-Django place to hang links to new server-side planner features. It could certainly be replaced or complemented with a nice index API method for rich JavaScript clients. """ context = {'plans': PLAN_MODEL.get().objects.filter(deleted=False), 'flight_names': getAllFlightNames(), 'exporters': choosePlanExporter.PLAN_EXPORTERS } return render_to_response( 'xgds_planner2/planIndex.html', getClassByName(settings.XGDS_PLANNER2_EDITOR_CONTEXT_METHOD)(context), context_instance=RequestContext(request))
def planIndex(request): """ For the moment this is a handy classic-Django place to hang links to new server-side planner features. It could certainly be replaced or complemented with a nice index API method for rich JavaScript clients. """ context = {'plans': PLAN_MODEL.get().objects.filter(deleted=False), 'flight_names': getAllFlightNames(), 'exporters': choosePlanExporter.PLAN_EXPORTERS } return render(request, 'xgds_planner2/planIndex.html', getClassByName(settings.XGDS_PLANNER2_EDITOR_CONTEXT_METHOD)(context), )
def getActiveEpisode(): """ Point to site settings to see real implementation of this function GET_ACTIVE_EPISODE """ active_flights = ACTIVE_FLIGHT_MODEL.get().objects.all() for active in active_flights: if active.flight.group: try: episode = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME)( active.flight.group.name) return episode except: pass return None
def getSegmentForTime(flightName, time): try: flightGroup, videoSource = flightName.split("_") source = SOURCE_MODEL.get().objects.get(shortName=videoSource) except: return None GET_EPISODE_FROM_NAME_METHOD = getClassByName(settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) if episode.endTime: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime__gte=time, source=source) return segment else: try: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime__gte=time, source=source) except: segment = SEGMENT_MODEL.get().objects.get(episode=episode, startTime__lte=time, endTime=None, source=source) return segment
def videoIndexFile(request, flightName=None, sourceShortName=None, segmentNumber=None): """ modifies index file of recorded video to the correct host. """ # Look up path to index file GET_INDEX_FILE_METHOD = getClassByName( settings.XGDS_VIDEO_INDEX_FILE_METHOD) suffix = GET_INDEX_FILE_METHOD(flightName, sourceShortName, segmentNumber) # use regex substitution to replace hostname, etc. newIndex = util.updateIndexFilePrefix(suffix, settings.SCRIPT_NAME, flightName) # return modified file in next line response = HttpResponse(newIndex, content_type="application/x-mpegurl") response['Content-Disposition'] = 'filename = "prog_index.m3u8"' return response
def captureStillImage(flightName, timestamp): stillLocationFxn = getClassByName(settings.XGDS_VIDEO_GPS_LOCATION_METHOD) locationInfo = stillLocationFxn(flightName, timestamp) (chunkPath, offsetInChunk) = getChunkfilePathAndOffsetForTime(flightName, timestamp) captureParams = { 'frameCaptureOffset': offsetInChunk, 'imageSubject': flightName, 'collectionTimeZoneName': settings.TIME_ZONE, 'outputDir': settings.IMAGE_CAPTURE_DIR, 'chunkFilePath': chunkPath, 'thumbnailSize': { 'width': 100, 'height': 56.25 }, 'contactInfo': 'http://www.pavilionlake.com', 'wallClockTime': calendar.timegm(timestamp.utctimetuple()), 'createThumbnail': True } if locationInfo: captureParams['locationInfo'] = { 'latitude': locationInfo.latitude, 'longitude': locationInfo.longitude, 'altitude': locationInfo.depthMeters } # # Now, send request for still frame capture # context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect(settings.XGDS_VIDEO_STILL_GRAB_SERVICE) if chunkPath: # did we really find a video chunk? If so, grab frame socket.send(json.dumps(captureParams)) resp = json.loads(socket.recv()) else: resp = {'captureSuccess': False, 'imageUuid': None} if resp['captureSuccess']: logging.info("Image capture OK for %s at %s" % (flightName, timestamp)) else: logging.info("Image capture failed for %s at %s" % (flightName, timestamp))
def grabFrameFromSource(request, episode, source): """ Look up the path and start time given a source and grab time. Pass this to xgds_image to grab frame and save image set. :param request: :param episode: the episode name :param source: the source short name :return: """ grab = request.POST.get('grab_time') if grab is None: result_dict = { 'status': 'error', 'error': 'You must specify video grab time.' } return JsonResponse(json.dumps(result_dict), status=httplib.NOT_ACCEPTABLE, safe=False) grab_time = dateparser(grab) grab_info = prepare_grab_frame(str(episode), str(source), grab_time) # print('GRAB FRAME FROM SOURCE %s' % grab_info) if grab_info: # modify request to have new information request.POST._mutable = True request.POST['path'] = grab_info['file_path'] # index file path request.POST['index_file_path'] = grab_info[ 'index_file_path'] # index file path request.POST['vehicle'] = grab_info['segment'].source.name request.POST['start_time'] = grab_info['segment'].startTime.isoformat() request.POST._mutable = False SAVE_IMAGE_FUNCTION = getClassByName( 'xgds_image.views.grab_frame_save_image') return SAVE_IMAGE_FUNCTION(request) result_dict = {'status': 'error', 'error': 'Could not find segment'} return JsonResponse(json.dumps(result_dict), status=httplib.NOT_ACCEPTABLE, safe=False)
def start(self): self.queryManager.subscribeDjango( self.parent.subscriber, lambda topic, obj: self.handleRecord(obj)) poseCollectorClass = getClassByName(self.meta['map']['poseCollector']) self.poseCollector = poseCollectorClass(self.parent.subscriber) self.running = True self.statusPath = os.path.join(self.outputDir, 'status.json') self.statusStore = plotUtil.JsonStore(self.statusPath) self.status = self.statusStore.read(dflt={ 'minTime': None, 'maxTime': None, 'numSamples': 0, 'numTiles': 0 }) self.batchProcessStartTime = time.time() if self.queueMode: self.batchIndex()
def start(self): self.queryManager.subscribeDjango(self.parent.subscriber, lambda topic, obj: self.handleRecord(obj)) poseCollectorClass = getClassByName(self.meta['map']['poseCollector']) self.poseCollector = poseCollectorClass(self.parent.subscriber) self.running = True self.statusPath = os.path.join(self.outputDir, 'status.json') self.statusStore = plotUtil.JsonStore(self.statusPath) self.status = self.statusStore.read(dflt={ 'minTime': None, 'maxTime': None, 'numSamples': 0, 'numTiles': 0 }) self.batchProcessStartTime = time.time() if self.queueMode: self.batchIndex()
def setSegmentEndTimes(segments, episode, source): """ If both the episode endtime and segments' endtimes are not available (we are live), set the segment end time as endTime value inferred from the index file Given dictionary of segments (key = source, value = segment). """ if not episode: print "CANNOT set segment end times for empty episode" + str(episode) return # for sourceShortName, segments in sourceSegmentsDict.iteritems(): flightName = episode.shortName + '_' + source.shortName # segments = sourceSegmentsDict[source.shortName] segments = sorted(segments, key=lambda segment: segment.segNumber) # if last segment has no endTime if (segments[-1].endTime is None) and (episode.endTime is None): segment = segments[-1] # last segment GET_INDEX_FILE_METHOD = getClassByName(settings.XGDS_VIDEO_INDEX_FILE_METHOD) suffix = GET_INDEX_FILE_METHOD(flightName, source.shortName, segment.segNumber) path = settings.DATA_ROOT + suffix segmentDuration = getTotalDuration(path) segment.endTime = segment.startTime + datetime.timedelta(seconds=segmentDuration) segment.save()
def record(request): if request.method == 'POST': form = NoteForm(request.POST) if form.is_valid(): data, tags, errors = getClassByName(settings.XGDS_NOTES_POPULATE_NOTE_DATA)(request, form) data = {str(k): v for k, v in data.items()} note = createNoteFromData(data) linkTags(note, tags) jsonNote = broadcastNote(note) if not settings.XGDS_SSE: return HttpResponse(jsonNote, content_type='application/json') else: return HttpResponse(json.dumps({'success': 'true'}), content_type='application/json') else: return HttpResponse(str(form.errors), status=400) # Bad Request else: raise Exception("Request method %s not supported." % request.method)
def recordSimple(request): if request.method != 'POST': return HttpResponse(json.dumps({'error': {'code': -32099, 'message': 'You must post, cheater.'} }), content_type='application/json') form = NoteForm(request.POST) if form.is_valid(): data, tags, errors = getClassByName(settings.XGDS_NOTES_POPULATE_NOTE_DATA)(request, form) note = createNoteFromData(data, False, 'serverNow' in request.POST) linkTags(note, tags) json_data = broadcastNote(note) #return JsonResponse(json_data, # status=200) return HttpResponse(json_data, content_type='application/json') else: return JsonResponse(json.dumps({'error': {'code': -32099, 'message': 'problem submitting note', 'data': form.errors} }), status=406)
def displayLiveVideo(request, sourceShortName=None): """ Directly display RTSP feeds for the active episode. This will either include all sources or be for a single source if it is passed in.. """ GET_ACTIVE_EPISODE_METHOD = getClassByName( settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) episode = GET_ACTIVE_EPISODE_METHOD() if not episode: messages.add_message(request, messages.ERROR, 'There is no live video.') return redirect(reverse('error')) sources = [] noteForms = [] if sourceShortName: try: source = SOURCE_MODEL.get().objects.get( shortName=str(sourceShortName)) sources.append(source) noteForms.append( buildNoteForm([episode], source, request, {'index': 0})) except: pass else: # get sources and get feeds sources = SOURCE_MODEL.get().objects.filter( videosegment__episode=episode).distinct() for index, source in enumerate(sources): noteForms.append( buildNoteForm([episode], source, request, {'index': index})) noteModelName = str(NOTE_MODEL.get().cls_type()) # noteForm = getClassByName(settings.XGDS_NOTES_BUILD_NOTES_FORM)({'vehicle__name':sourceShortName, # 'flight__group_name':episode.shortName}) theFilter = {} if settings.XGDS_VIDEO_NOTE_FILTER_FUNCTION: noteFilterFn = getClassByName(settings.XGDS_VIDEO_NOTE_FILTER_FUNCTION) theFilter = noteFilterFn(episode, sourceShortName) searchForms = getSearchForms(noteModelName, theFilter) ctx = { 'episode': episode, 'isLive': True, 'zipped': zip(sources, noteForms), 'SSE': settings.XGDS_SSE, 'modelName': noteModelName, 'flightName': episode.shortName, 'flightTZ': settings.TIME_ZONE, 'searchModelDict': { noteModelName: settings.XGDS_MAP_SERVER_JS_MAP[noteModelName] }, 'searchForms': searchForms, # 'searchForms': {noteModelName: [noteForm,settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]] }, 'app': 'xgds_video/js/mapVideoApp.js', 'templates': get_handlebars_templates( list(settings.XGDS_MAP_SERVER_HANDLEBARS_DIRS), 'XGDS_MAP_SERVER_HANDLEBARS_DIRS'), } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName( settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) theTemplate = 'xgds_video/map_live_playbacks.html' return render(request, theTemplate, ctx)
def endActiveEpisode(end_time): episode = getClassByName(settings.XGDS_VIDEO_GET_ACTIVE_EPISODE)() if episode: episode.endTime = end_time episode.save()
def schedulePlans(request, redirect=True): flight = None lastPlanExecution = None pe = None if request.method == 'POST': try: pids = request.POST['planIds'] planIds = [] for item in pids.split(","): planIds.append(int(item)) plans = PLAN_MODEL.get().objects.filter(id__in=planIds) if 'planExecutionId' in request.POST and request.POST['planExecutionId'] != '': pe = PLAN_EXECUTION_MODEL.get().objects.get(pk=int(request.POST['planExecutionId'])) schedule_date_string = request.POST['schedule_date'] original_schedule_date = None prefix = None if schedule_date_string: # read the date; it comes in as UTC original_schedule_date = dateparser(schedule_date_string) original_schedule_date = pytz.utc.localize(original_schedule_date) schedule_date = original_schedule_date if pe: firstPlan = pe.plan else: firstPlan = plans[0] local_date = utcToTimeZone(original_schedule_date, str(firstPlan.jsonPlan.site.alternateCrs.properties.timezone)) prefix = "%04d%02d%02d" % (local_date.year, local_date.month, local_date.day) flight_name = request.POST['flight'] # see if flight name matches prefix, if not go by the date if prefix and flight_name: if not flight_name.startswith(prefix): flight_name = None try: flight = FLIGHT_MODEL.get().objects.get(name=flight_name) except FLIGHT_MODEL.get().DoesNotExist: # see if we can look it up by date if original_schedule_date: flights = FLIGHT_MODEL.get().objects.filter(name__startswith=prefix) if flights: # pick the first one flight = flights[0] else: # it does not exist we better make one prefix = prefix + "A" groupFlight, created = GROUP_FLIGHT_MODEL.get().objects.get_or_create(name=prefix) for vehicle in VEHICLE_MODEL.get().objects.all(): newFlight = FLIGHT_MODEL.get()() newFlight.group = groupFlight newFlight.vehicle = vehicle newFlight.name = prefix + "_" + vehicle.name newFlight.locked = False newFlight.uuid = uuid4() newFlight.save(force_insert=True) if not flight: flight = newFlight if flight: for plan in plans: if not pe: pe = PLAN_EXECUTION_MODEL.get()() pe.planned_start_time = schedule_date pe.flight = flight pe.plan = plan if settings.XGDS_PLANNER2_SCHEDULE_EXTRAS_METHOD: pe = getClassByName(settings.XGDS_PLANNER2_SCHEDULE_EXTRAS_METHOD)(request, pe) pe.save() lastPlanExecution = pe except: traceback.print_exc() return HttpResponse(json.dumps({'Success':"False", 'msg': 'Plan not scheduled'}), content_type='application/json', status=406) pass if redirect: return HttpResponseRedirect(reverse('planner2_index')) else: if lastPlanExecution: return HttpResponse(json.dumps(lastPlanExecution.toSimpleDict(), cls=DatetimeJsonEncoder), content_type='application/json') return HttpResponse(json.dumps({'Success':"True", 'msg': 'Plan scheduled'}), content_type='application/json')
def schedulePlans(request, redirect=True): flight = None lastPlanExecution = None pe = None if request.method == 'POST': try: pids = request.POST['planIds'] planIds = [] for item in pids.split(","): planIds.append(int(item)) plans = PLAN_MODEL.get().objects.filter(id__in=planIds) if 'planExecutionId' in request.POST and request.POST['planExecutionId'] != '': pe = PLAN_EXECUTION_MODEL.get().objects.get(pk=int(request.POST['planExecutionId'])) schedule_date_string = request.POST['schedule_date'] original_schedule_date = None prefix = None if schedule_date_string: # read the date; it comes in as UTC original_schedule_date = dateparser(schedule_date_string) original_schedule_date = pytz.utc.localize(original_schedule_date) schedule_date = original_schedule_date if pe: firstPlan = pe.plan else: firstPlan = plans[0] local_date = utcToTimeZone(original_schedule_date, str(firstPlan.jsonPlan.site.alternateCrs.properties.timezone)) prefix = "%04d%02d%02d" % (local_date.year, local_date.month, local_date.day) flight_name = request.POST['flight'] # see if flight name matches prefix, if not go by the date if prefix and flight_name: if not flight_name.startswith(prefix): flight_name = None try: flight = FLIGHT_MODEL.get().objects.get(name=flight_name) except FLIGHT_MODEL.get().DoesNotExist: # see if we can look it up by date if original_schedule_date: flights = FLIGHT_MODEL.get().objects.filter(name__startswith=prefix) if flights: # pick the first one flight = flights[0] else: # it does not exist we better make one prefix = prefix + "A" groupFlight, created = GROUP_FLIGHT_MODEL.get().objects.get_or_create(name=prefix) for vehicle in VEHICLE_MODEL.get().objects.all(): newFlight = FLIGHT_MODEL.get()() newFlight.group = groupFlight newFlight.vehicle = vehicle newFlight.name = prefix + "_" + vehicle.name newFlight.locked = False newFlight.uuid = uuid4() newFlight.save(force_insert=True) if not flight: flight = newFlight if flight: for plan in plans: if not pe: pe = PLAN_EXECUTION_MODEL.get()() pe.planned_start_time = schedule_date pe.flight = flight pe.plan = plan if settings.XGDS_PLANNER2_SCHEDULE_EXTRAS_METHOD: pe = getClassByName(settings.XGDS_PLANNER2_SCHEDULE_EXTRAS_METHOD)(request, pe) pe.save() lastPlanExecution = pe except: traceback.print_exc() return HttpResponse(json.dumps({'Success':"False", 'msg': 'Plan not scheduled'}), content_type='application/json', status=406) pass if redirect: return HttpResponseRedirect(reverse('planner2_index')) else: if lastPlanExecution: return HttpResponse(json.dumps(lastPlanExecution.toSimpleDict(), cls=DatetimeJsonEncoder), content_type='application/json') return HttpResponse(json.dumps({'Success':"True", 'msg': 'Plan scheduled'}), content_type='application/json')
return name[:dot], name[dot + 1:] class ImporterInfo(object): def __init__(self, formatCode, extension, importerClass): self.formatCode = formatCode self.extension = extension self.importerClass = importerClass self.label = importerClass.label PLAN_IMPORTERS = [] PLAN_IMPORTERS_BY_FORMAT = {} for _formatCode, _extension, _importerClassName in settings.XGDS_PLANNER_PLAN_IMPORTERS: _importerInfo = ImporterInfo(_formatCode, _extension, getClassByName(_importerClassName)) PLAN_IMPORTERS.append(_importerInfo) PLAN_IMPORTERS_BY_FORMAT[_formatCode] = _importerInfo def chooseImporter(name, formatCode=None): if formatCode is not None: importerClass = PLAN_IMPORTERS_BY_FORMAT.get(formatCode) else: importerClass = None for entry in PLAN_IMPORTERS: if name.endswith(entry.extension): importerClass = entry.importerClass break return importerClass
def getIndexFileContents(flightName=None, sourceShortName=None, segmentNumber=None, forceEndlist=False): """ This is truncating the last n rows from the m3u8 file and reappending the end and the metadata at the top. This fakes our delay """ # Look up path to index file GET_INDEX_FILE_METHOD = getClassByName(settings.XGDS_VIDEO_INDEX_FILE_METHOD) indexFileSuffix, segment = GET_INDEX_FILE_METHOD(flightName, sourceShortName, segmentNumber) indexFilePath = os.path.join(settings.DATA_ROOT, indexFileSuffix) segmentDirectoryUrl = settings.DATA_URL + os.path.dirname(indexFileSuffix) valid = False try: videoDelayInSecs = getClassByName(settings.XGDS_VIDEO_DELAY_AMOUNT_METHOD)(flightName) if videoDelayInSecs > 0: calculatedDelay = videoDelayInSecs #if the segment is ended then this may want to be different if segment.endTime: # 1. calculate secondsAgo = nowTime - segment.endTime secondsAgo = (timezone.now() - segment.endTime).total_seconds() # 2. if secondsAgo < delay, calculatedDelay = videoDelayInSecs - secondsAgo calculatedDelay = max(videoDelayInSecs - secondsAgo, 0) if calculatedDelay > 0: (videoDelayInChunks, m3u8_index, valid) = getNumChunksFromEndForDelay(calculatedDelay - getFudgeForSource(sourceShortName), indexFilePath) if videoDelayInChunks > 0: m3u8_index.is_endlist = False else: # I *think* we should only get here if we have signal loss during a live feed and are playing out the last # bit of playlist in which case we *should* add an end tag. try: if segment.endTime: m3u8_index = m3u8.load(indexFilePath) if segment.episode.endTime: m3u8_index.is_endlist = True valid = True videoDelayInChunks = 0 #TODO broadcast segment end, show glitch in progress screen except: traceback.print_exc() else: try: m3u8_index = m3u8.load(indexFilePath) if forceEndlist: m3u8_index.is_endlist = True videoDelayInChunks = 0 valid = True except: traceback.print_exc() if not valid: if m3u8_index: try: m3u8_index.segments = None except: pass return (m3u8_index.dumps(), indexFilePath) else: return (None, None) m3u8_chunks = m3u8_index.segments if m3u8_chunks and len(m3u8_chunks) > 0: # this was probably to handle vlc badness # if segments[0].duration > 100: # del segments[0] if videoDelayInChunks > 0: # and len(m3u8_chunks) > videoDelayInChunks: del m3u8_chunks[-videoDelayInChunks:] del m3u8_chunks[:-settings.XGDS_VIDEO_LIVE_PLAYLIST_SIZE_TO_PLAYER] if m3u8_chunks: firstSegNum = getSegmentNumber(m3u8_index.segments[0]) else: firstSegNum = 0 m3u8_index.media_sequence = firstSegNum for s in m3u8_chunks: s.uri = str(segmentDirectoryUrl) + '/' + s.uri return (m3u8_index.dumps(), indexFilePath) except: #TODO handle better traceback.print_exc() traceback.print_stack() return (None, None)
def getVideoContext(request, flightName=None, sourceShortName=None, time=None): requestedTime = "" active = False episode = {} if time is not None: # TODO: this is a duplicate path for playing back video at a certain time, it is legacy from PLRP # and was not fully working there; merge these 2 ways of playing back from a time. # time is passed as string (yy-mm-dd hh:mm:ss) try: requestedTime = datetime.datetime.strptime(time, "%Y-%m-%d %H:%M:%S") except: try: requestedTime = datetime.datetime.strptime( time, "%Y-%m-%d %H:%M:%S+00:00") except: requestedTime = dateparse.parse_datetime(time) GET_ACTIVE_EPISODE_METHOD = getClassByName( settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) activeepisode = GET_ACTIVE_EPISODE_METHOD() # this happens when user clicks on a flight name to view video if flightName: try: GET_EPISODE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) if not episode: raise Exception('no episode') if episode and episode == activeepisode: active = True except: return {} # this happens when user looks for live recorded if not episode: episode = activeepisode active = True if not episode: message = 'Video not found' if flightName: message += ' for ' + flightName else: message += ': no live video' messages.add_message(request, messages.ERROR, message) return redirect(reverse('error')) if episode: if not flightName: flightName = episode.shortName # get the segments segments = episode.videosegment_set.all() if not segments: msg = 'Video segments not found ' if flightName: msg = msg + flightName return recordedVideoError(request, msg) sourceShortName = str(sourceShortName) if sourceShortName == 'None': sourceShortName = None if sourceShortName: try: source = SOURCE_MODEL.get().objects.get(shortName=sourceShortName) segments = segments.filter(source=source) except: pass sources = [] segmentsDict = {} # dictionary of segments (in JSON) within given episode sourceVehicle = {} index = 0 distinctSources = segments.values('source').distinct() for sourceDict in distinctSources: source = SOURCE_MODEL.get().objects.get(pk=sourceDict['source']) sources.append(source) sourceVehicle[source.shortName] = source.vehicleName sourceSegments = segments.filter(source=source) segmentsDict[source.shortName] = [ seg.getDict() for seg in sourceSegments ] form = buildNoteForm([episode], source, request, {'index': index}) source.form = form index = index + 1 if flightName: if flightName.find('_') == -1: fullFlightName = flightName + "_" + sources[0].shortName else: fullFlightName = flightName GET_TIMEZONE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_TIMEZONE_FROM_NAME) flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(str(fullFlightName)) else: flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(None) if not segmentsDict: return recordedVideoError(request, "No video segments found " + flightName) segmentsJson = json.dumps(segmentsDict, sort_keys=True, indent=4, cls=DatetimeJsonEncoder) episodeJson = json.dumps(episode.getDict(), cls=DatetimeJsonEncoder) noteModelName = str(NOTE_MODEL.get().cls_type()) noteForm = getClassByName(settings.XGDS_NOTES_BUILD_NOTES_FORM)( { 'vehicle__name': sourceShortName, 'flight__group_name': episode.shortName } ) #TODO this assumes the episode short name and group flight name are the same ctx = { 'segmentsJson': segmentsJson, 'isLive': active, 'episode': episode, 'episodeJson': episodeJson, 'noteTimeStamp': requestedTime, # in string format yy-mm-dd hh:mm:ss (in utc. converted to local time in js) 'sources': sources, 'flightName': flightName, 'flightTZ': flightTimezone, 'sourceVehicle': json.dumps(sourceVehicle), 'SSE': settings.XGDS_SSE, 'modelName': noteModelName, 'searchModelDict': { noteModelName: settings.XGDS_MAP_SERVER_JS_MAP[noteModelName] }, 'searchForms': { noteModelName: [noteForm, settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]] }, 'app': 'xgds_video/js/mapVideoApp.js', 'templates': get_handlebars_templates( list(settings.XGDS_MAP_SERVER_HANDLEBARS_DIRS), 'XGDS_MAP_SERVER_HANDLEBARS_DIRS'), } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName( settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) return ctx
return name[:dot], name[dot + 1:] class ImporterInfo(object): def __init__(self, formatCode, extension, importerClass): self.formatCode = formatCode self.extension = extension self.importerClass = importerClass self.label = importerClass.label PLAN_IMPORTERS = [] PLAN_IMPORTERS_BY_FORMAT = {} for _formatCode, _extension, _importerClassName in settings.XGDS_PLANNER_PLAN_IMPORTERS: _importerInfo = ImporterInfo(_formatCode, _extension, getClassByName(_importerClassName)) PLAN_IMPORTERS.append(_importerInfo) PLAN_IMPORTERS_BY_FORMAT[_formatCode] = _importerInfo def chooseImporter(name, formatCode=None): if formatCode is not None: importerClass = PLAN_IMPORTERS_BY_FORMAT.get(formatCode) else: importerClass = None for entry in PLAN_IMPORTERS: if name.endswith(entry.extension): importerClass = entry.importerClass break return importerClass
def displayRecordedVideo(request, flightName=None, sourceShortName=None, time=None): """ TODO flightName is actually groupName """ """ Returns first segment of all sources that are part of a given episode. Used for both playing back videos from active episode and also for playing videos associated with each note. """ requestedTime = "" active = False episode = {} if time is not None: # TODO: this is a duplicate path for playing back video at a certain time, it is legacy from PLRP # and was not fully working there; merge these 2 ways of playing back from a time. # time is passed as string (yy-mm-dd hh:mm:ss) try: requestedTime = datetime.datetime.strptime(time, "%Y-%m-%d %H:%M:%S") except: requestedTime = dateparse.parse_datetime(time) requestedTime = util.pythonDatetimeToJSON( requestedTime) # util.convertUtcToLocal(requestedTime)) GET_ACTIVE_EPISODE_METHOD = getClassByName( settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) activeepisode = GET_ACTIVE_EPISODE_METHOD() # this happens when user clicks on a flight name to view video if flightName: GET_EPISODE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) if (episode != None and episode == activeepisode): active = True # this happens when user looks for live recorded if not episode: episode = activeepisode active = True if not episode: message = 'Video not found' if flightName: message += ' for ' + flightName else: message += ': no live video' messages.add_message(request, messages.ERROR, message) return redirect(reverse('error')) if episode: if not flightName: flightName = episode.shortName # get the segments segments = episode.videosegment_set.all() if not segments: msg = 'Video segments not found ' if flightName: msg = msg + flightName return recordedVideoError(request, msg) sourceShortName = str(sourceShortName) if sourceShortName: try: source = SOURCE_MODEL.get().objects.get(shortName=sourceShortName) segments = segments.filter(source=source) except: pass sources = [] segmentsDict = {} # dictionary of segments (in JSON) within given episode sourceVehicle = {} index = 0 distinctSources = segments.values('source').distinct() for sourceDict in distinctSources: source = SOURCE_MODEL.get().objects.get(pk=sourceDict['source']) sources.append(source) sourceVehicle[source.shortName] = source.vehicleName sourceSegments = segments.filter(source=source) segmentsDict[source.shortName] = [ seg.getDict() for seg in sourceSegments ] form = buildNoteForm([episode], source, request, {'index': index}) source.form = form index = index + 1 if flightName: if flightName.find('_') == -1: fullFlightName = flightName + "_" + sources[0].shortName else: fullFlightName = flightName GET_TIMEZONE_FROM_NAME_METHOD = getClassByName( settings.XGDS_VIDEO_GET_TIMEZONE_FROM_NAME) flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(str(fullFlightName)) else: flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(None) if not segmentsDict: return recordedVideoError(request, "No video segments found " + flightName) segmentsJson = json.dumps(segmentsDict, sort_keys=True, indent=4, cls=DatetimeJsonEncoder) episodeJson = json.dumps(episode.getDict()) theTemplate = 'xgds_video/video_recorded_playbacks.html' if active: theTemplate = 'xgds_video/video_active_playbacks.html' ctx = { 'segmentsJson': segmentsJson, 'episode': episode, 'isLive': active, 'episodeJson': episodeJson, 'noteTimeStamp': requestedTime, # in string format yy-mm-dd hh:mm:ss (in utc. converted to local time in js) 'sources': sources, 'flightName': flightName, 'flightTZ': flightTimezone, 'sourceVehicle': json.dumps(sourceVehicle), 'SSE': settings.XGDS_SSE } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName( settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) return render_to_response(theTemplate, ctx, context_instance=RequestContext(request))
from geocamUtil import loader class ExporterInfo(object): def __init__(self, formatCode, extension, exporterClass, customLabel=None): self.formatCode = formatCode self.extension = extension self.exporterClass = exporterClass if customLabel: self.label = customLabel else: self.label = exporterClass.label self.url = None PLAN_EXPORTERS = [] PLAN_EXPORTERS_BY_FORMAT = {} for exporterInfo in settings.XGDS_PLANNER_PLAN_EXPORTERS: # _formatCode, _extension, _exporterClassName, _customLabel _formatCode = exporterInfo[0] _extension = exporterInfo[1] _exporterClassName = exporterInfo[2] _customLabel = None if len(exporterInfo) > 3: _customLabel = exporterInfo[3] _exporterInfo = ExporterInfo(_formatCode, _extension, loader.getClassByName(_exporterClassName), _customLabel) PLAN_EXPORTERS.append(_exporterInfo) PLAN_EXPORTERS_BY_FORMAT[_formatCode] = _exporterInfo
def callGetNoteExtras(episodes, source, request): if settings.XGDS_VIDEO_NOTE_EXTRAS_FUNCTION: noteExtrasFn = getClassByName(settings.XGDS_VIDEO_NOTE_EXTRAS_FUNCTION) return noteExtrasFn(episodes, source, request) else: return None
def callGetNoteExtras(episodes, source, request): if settings.XGDS_VIDEO_NOTE_EXTRAS_FUNCTION: noteExtrasFn = getClassByName(settings.XGDS_VIDEO_NOTE_EXTRAS_FUNCTION) return noteExtrasFn(episodes, source, request) else: return None
def displayRecordedVideo(request, flightName=None, sourceShortName=None, time=None): """ TODO flightName is actually groupName """ """ Returns first segment of all sources that are part of a given episode. Used for both playing back videos from active episode and also for playing videos associated with each note. """ requestedTime = "" active = False episode = {} if time is not None: # TODO: this is a duplicate path for playing back video at a certain time, it is legacy from PLRP # and was not fully working there; merge these 2 ways of playing back from a time. # time is passed as string (yy-mm-dd hh:mm:ss) try: requestedTime = datetime.datetime.strptime(time, "%Y-%m-%d %H:%M:%S") except: requestedTime = dateparse.parse_datetime(time) requestedTime = util.pythonDatetimeToJSON(requestedTime) # util.convertUtcToLocal(requestedTime)) GET_ACTIVE_EPISODE_METHOD = getClassByName(settings.XGDS_VIDEO_GET_ACTIVE_EPISODE) activeepisode = GET_ACTIVE_EPISODE_METHOD() # this happens when user clicks on a flight name to view video if flightName: GET_EPISODE_FROM_NAME_METHOD = getClassByName(settings.XGDS_VIDEO_GET_EPISODE_FROM_NAME) episode = GET_EPISODE_FROM_NAME_METHOD(flightName) if (episode != None and episode == activeepisode): active = True # this happens when user looks for live recorded if not episode: episode = activeepisode active = True if not episode: message = 'Video not found' if flightName: message += ' for ' + flightName else: message += ': no live video' messages.add_message(request, messages.ERROR, message) return redirect(reverse('error')) if episode: if not flightName: flightName = episode.shortName # get the segments segments = episode.videosegment_set.all() if not segments: msg = 'Video segments not found ' if flightName: msg = msg + flightName return recordedVideoError(request, msg) sourceShortName = str(sourceShortName) if sourceShortName == 'None': sourceShortName = None if sourceShortName: try: source = SOURCE_MODEL.get().objects.get(shortName=sourceShortName) segments = segments.filter(source=source) except: pass sources = [] segmentsDict = {} # dictionary of segments (in JSON) within given episode sourceVehicle = {} index = 0 distinctSources = segments.values('source').distinct() for sourceDict in distinctSources: source = SOURCE_MODEL.get().objects.get(pk=sourceDict['source']) sources.append(source) sourceVehicle[source.shortName] = source.vehicleName sourceSegments = segments.filter(source=source) segmentsDict[source.shortName] = [seg.getDict() for seg in sourceSegments] form = buildNoteForm([episode], source, request, {'index':index}) source.form = form index = index + 1 if flightName: if flightName.find('_') == -1: fullFlightName = flightName + "_" + sources[0].shortName else: fullFlightName = flightName GET_TIMEZONE_FROM_NAME_METHOD = getClassByName(settings.XGDS_VIDEO_GET_TIMEZONE_FROM_NAME) flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(str(fullFlightName)) else: flightTimezone = GET_TIMEZONE_FROM_NAME_METHOD(None) if not segmentsDict: return recordedVideoError(request, "No video segments found " + flightName) segmentsJson = json.dumps(segmentsDict, sort_keys=True, indent=4, cls=DatetimeJsonEncoder) episodeJson = json.dumps(episode.getDict()) theTemplate = 'xgds_video/map_recorded_playbacks.html' if active: theTemplate = 'xgds_video/map_active_playbacks.html' noteModelName = str(NOTE_MODEL.get().cls_type()) noteForm = getClassByName(settings.XGDS_NOTES_BUILD_NOTES_FORM)({'vehicle__name':sourceShortName, 'flight__group_name':flightName}) ctx = { 'segmentsJson': segmentsJson, 'episode': episode, 'isLive': active, 'episodeJson': episodeJson, 'noteTimeStamp': requestedTime, # in string format yy-mm-dd hh:mm:ss (in utc. converted to local time in js) 'sources': sources, 'flightName': flightName, 'flightTZ': flightTimezone, 'sourceVehicle': json.dumps(sourceVehicle), 'SSE': settings.XGDS_SSE, 'modelName': noteModelName, 'searchModelDict': {noteModelName:settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]}, 'searchForms': {noteModelName: [noteForm,settings.XGDS_MAP_SERVER_JS_MAP[noteModelName]] }, 'app': 'xgds_map_server/js/search/mapViewerSearchApp.js', 'templates': get_handlebars_templates(list(settings.XGDS_MAP_SERVER_HANDLEBARS_DIRS), 'XGDS_MAP_SERVER_HANDLEBARS_DIRS'), } if settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT: extraVideoContextFn = getClassByName(settings.XGDS_VIDEO_EXTRA_VIDEO_CONTEXT) extraVideoContextFn(ctx) return render_to_response(theTemplate, ctx, context_instance=RequestContext(request))
from geocamTrack.models import ResourcePosition, PastResourcePosition, Centroid, HeadingMixin import geocamTrack.models from geocamTrack.avatar import renderAvatar from django.conf import settings import traceback from trackUtil import getDatesWithPositionData from xgds_core.util import insertIntoPath if False and settings.XGDS_SSE: from sse_wrapper.events import send_event TRACK_MODEL = LazyGetModelByName(settings.GEOCAM_TRACK_TRACK_MODEL) POSITION_MODEL = LazyGetModelByName(settings.GEOCAM_TRACK_POSITION_MODEL) PAST_POSITION_MODEL = LazyGetModelByName(settings.GEOCAM_TRACK_PAST_POSITION_MODEL) RECENT_TIME_FUNCTION = getClassByName(settings.GEOCAM_TRACK_RECENT_TIME_FUNCTION) VEHICLE_MODEL = LazyGetModelByName(settings.XGDS_CORE_VEHICLE_MODEL) ACTIVE_FLIGHT_MODEL = LazyGetModelByName(settings.XGDS_CORE_ACTIVE_FLIGHT_MODEL) class ExampleError(Exception): pass def getIndex(request): return render(request, 'trackingIndex.html', {} )
class ExporterInfo(object): def __init__(self, formatCode, extension, exporterClass, customLabel=None): self.formatCode = formatCode self.extension = extension self.exporterClass = exporterClass if customLabel: self.label = customLabel else: self.label = exporterClass.label self.url = None PLAN_EXPORTERS = [] PLAN_EXPORTERS_BY_FORMAT = {} for exporterInfo in settings.XGDS_PLANNER_PLAN_EXPORTERS: # _formatCode, _extension, _exporterClassName, _customLabel _formatCode = exporterInfo[0] _extension = exporterInfo[1] _exporterClassName = exporterInfo[2] _customLabel = None if len(exporterInfo) > 3: _customLabel = exporterInfo[3] _exporterInfo = ExporterInfo(_formatCode, _extension, loader.getClassByName(_exporterClassName), _customLabel) PLAN_EXPORTERS.append(_exporterInfo) PLAN_EXPORTERS_BY_FORMAT[_formatCode] = _exporterInfo
def getSortOrder(): if settings.XGDS_NOTES_SORT_FUNCTION: noteSortFn = getClassByName(settings.XGDS_NOTES_SORT_FUNCTION) return noteSortFn() else: return getattr(settings, 'XGDS_NOTES_REVIEW_DEFAULT_SORT', '-event_time')