def schedule_object(request): log = logging.getLogger('abcast.schedulerviews.schedule_object') if not request.user.has_perm('abcast.schedule_emission'): log.warning('unauthorized attempt to schedule emission by: %s' % request.user) return { 'message': _('Sorry - you are not allowed to schedule an emission.') } ct = request.POST.get('ct', None) obj_id = request.POST.get('obj_id', None) top = request.POST.get('top', None) left = request.POST.get('left', None) range_start = request.POST.get('range_start', None) range_end = request.POST.get('range_end', None) channel_id = request.POST.get('channel_id', SCHEDULER_DEFAULT_CHANNEL_ID) channel = Channel.objects.get(pk=channel_id) color = request.POST.get('color', 0) num_days = request.POST.get('num_days', SCHEDULER_NUM_DAYS) log.debug('content type: %s' % ct) if ct == 'playlist': obj = Playlist.objects.get(pk=int(obj_id)) log.debug('object to schedule: %s' % obj.name) if not (obj.broadcast_status == 1 and obj.type == 'broadcast'): log.warning('attempt to shedule invalid playlist. pk: %s' % obj.pk) return { 'message': _('Sorry - this playlist does not meet all criterias to be scheduled.') } pph = SCHEDULER_PPH # ppd = SCHEDULER_PPD ppd = (SCHEDULER_GRID_WIDTH - SCHEDULER_GRID_OFFSET) / int(num_days) top = float(top) / pph * 60 offset_min = int(15 * round(float(top)/15)) left = float(left) / ppd offset_d = int(round(float(left))) log.debug('minutes (offset): %s' % offset_min) log.debug('days (offset): %s' % offset_d) # calculate actual date/time for position schedule_start = datetime.datetime.strptime('%s 00:00' % range_start, '%Y-%m-%d %H:%M') # add offsets time_start = schedule_start + datetime.timedelta(minutes=offset_min) time_start = time_start + datetime.timedelta(days=offset_d) time_start = time_start + datetime.timedelta(hours=SCHEDULER_OFFSET) # time_end = time_start + datetime.timedelta(milliseconds=obj.get_duration()) # for duration calculation we use the 'target duration' (to avoid blocked slots) time_end = time_start + datetime.timedelta(seconds=(obj.target_duration)) log.debug('time_start: %s' % time_start) log.debug('time_end: %s' % time_end) # check if in past now = datetime.datetime.now() lock_end = now + datetime.timedelta(seconds=SCHEDULER_LOCK_AHEAD) if lock_end > time_start: return { 'message': _('You cannot schedule emissions in the past.') } # check if slot is free # hm just allow some seconds of tolerance (in case of mini-overlaps) es = Emission.objects.filter( time_end__gt=time_start + datetime.timedelta(seconds=OVERLAP_TOLERANCE), time_start__lt=time_end, channel=channel) if es.count() > 0: message = _('The desired time slot does not seem to be available.') try: message += u'<br>Emission schedule "%s" - from %s to %s' % (e.name, time_start.time(), time_end.time()) for conflicting_emission in es: message += u'<br> - overlaps "%s" - from %s to %s' % (conflicting_emission.name, conflicting_emission.time_start.time(), conflicting_emission.time_end.time()) except: pass return { 'message': message } # if no errors so far -> create emission and attach object e = Emission(content_object=obj, time_start=time_start, user=request.user, channel=channel, color=color) e.save() action.send(request.user, verb='scheduled', target=e.content_object) data = { 'status': True, 'obj_id': obj_id } return data
def schedule_object(request): if not request.user.has_perm('abcast.schedule_emission'): log.warning('unauthorized attempt to schedule emission by: %s' % request.user) data = { 'message': _('Sorry - you are not allowed to schedule an emission.') } return HttpResponse(json.dumps(data), content_type='application/json') data = json.loads(request.body) ct = data.get('ct', None) obj_id = data.get('obj_id', None) top = data.get('top', None) left = data.get('left', None) range_start = data.get('range_start', None) range_end = data.get('range_end', None) channel_id = data.get('channel_id', SCHEDULER_DEFAULT_CHANNEL_ID) channel = Channel.objects.get(pk=channel_id) color = data.get('color', 0) num_days = data.get('num_days', SCHEDULER_NUM_DAYS) log.debug('content type: %s' % ct) if ct == 'playlist': obj = Playlist.objects.get(pk=int(obj_id)) log.debug('object to schedule: %s' % obj.name) if not (obj.broadcast_status == 1 and obj.type == 'broadcast'): log.warning('attempt to shedule invalid playlist. pk: %s' % obj.pk) return { 'message': _('Sorry - this playlist does not meet all criterias to be scheduled.') } pph = SCHEDULER_PPH ppd = (SCHEDULER_GRID_WIDTH - SCHEDULER_GRID_OFFSET) / int(num_days) top = float(top) / pph * 60 offset_min = int(15 * round(float(top)/15)) left = float(left) / ppd offset_d = int(round(float(left))) log.debug('minutes (offset): %s' % offset_min) log.debug('days (offset): %s' % offset_d) # calculate actual date/time for position schedule_start = datetime.datetime.strptime('%s 00:00' % range_start, '%Y-%m-%d %H:%M') # add offsets time_start = schedule_start + datetime.timedelta(minutes=offset_min) time_start = time_start + datetime.timedelta(days=offset_d) time_start = time_start + datetime.timedelta(hours=SCHEDULER_OFFSET) # time_end = time_start + datetime.timedelta(milliseconds=obj.get_duration()) # for duration calculation we use the 'target duration' (to avoid blocked slots) time_end = time_start + datetime.timedelta(seconds=obj.target_duration) log.debug('time_start: %s' % time_start) log.debug('time_end: %s' % time_end) # check if in past now = datetime.datetime.now() lock_end = now + datetime.timedelta(seconds=SCHEDULER_LOCK_AHEAD) if lock_end > time_start: return { 'message': _('You cannot schedule emissions in the past.') } # check if slot is free # hm just allow some seconds of tolerance (in case of mini-overlaps) es = Emission.objects.filter( time_end__gt=time_start + datetime.timedelta(seconds=OVERLAP_TOLERANCE), time_start__lt=time_end, channel=channel) if es.count() > 0: message = _('The desired time slot does not seem to be available.') try: message += u'<br>Emission schedule from %s to %s' % (time_start.time(), time_end.time()) for conflicting_emission in es: message += u'<br> - overlaps "%s" - from %s to %s' % (conflicting_emission.name, conflicting_emission.time_start.time(), conflicting_emission.time_end.time()) except: pass return { 'message': message } # if no errors so far -> create emission and attach object e = Emission(content_object=obj, time_start=time_start, user=request.user, channel=channel, color=color) e.save() action.send(request.user, verb='scheduled', target=e.content_object) data = { 'status': True, 'obj_id': obj_id } return HttpResponse(json.dumps(data), content_type='application/json')
def schedule_daypart(self, daypart): log.info('Scheduling daypart: {abs_time_start}-{abs_time_end} - Weekday: {weekday}"'.format(**daypart)) daypart_duration = (daypart['abs_time_end'] - daypart['abs_time_start']) log.debug('Slot duration: {:} seconds'.format(daypart_duration.seconds)) theme = 3 if daypart['abs_time_start'].hour in [7, 19]: theme = 1 if daypart['abs_time_start'].hour == 12: theme = 2 if daypart['abs_time_start'].hour == 0: theme = 0 # get applying dayparts & playlists for current slot daypart_qs = self.get_daypart_qs( weekday=daypart['weekday'], time_start=daypart['abs_time_start'], time_end=daypart['abs_time_end'], ) next_start = daypart['abs_time_start'] num_tries = 0 while next_start and next_start < daypart['abs_time_end']: if num_tries > 20: raise IOError('io 10??') # needs to be re-fetched in every loop playlists_qs = self.get_playlist_qs(dayparts=daypart_qs) if not playlists_qs.exists(): next_start = None else: max_min_durations = playlists_qs.values("target_duration").aggregate( max=Max('target_duration'), min=Min('target_duration') ) next_start, next_end, min_duration, slot_duration = self.get_next_slot( time_start=daypart['abs_time_start'], time_end=daypart['abs_time_end'], min_duration=max_min_durations.get('min', 0) ) if next_start: qs = playlists_qs.filter(target_duration__lte=slot_duration) if qs.exists(): playlists = list(qs.order_by('?')) shuffle(playlists) playlist = playlists[0] #playlist = qs.order_by('?')[0] log.info('Scheduling at {:} - pk: {:} "{:}"'.format(next_start, playlist.pk, playlist.name)) emission = Emission( content_object=playlist, time_start=next_start, channel=self.channel, user=self.user, color=theme ) emission.save() self.add_playlist_exclude(playlist.pk) self.add_scheduled_emission(emission) time.sleep(1) num_tries += 1
def add_emissions(self, abs_start, abs_end): slot_duration = (abs_end - abs_start).seconds slot_time_left = slot_duration slot_time_offset = 0 print 'adding emissions to slot: %s to %s' % (abs_start, abs_end) print 'weekday: %s' % abs_start.weekday() print 'slot_duration: %s' % slot_duration from abcast.models import Emission from alibrary.models import Playlist # look for playlists that match daypart criterias # pl_dayparts query from alibrary.models import Daypart as PlaylistDaypart pldps = PlaylistDaypart.objects.filter( day=abs_start.weekday(), time_start__lte=abs_start.time(), time_end__gte=abs_end.time() ) # very ugly. but no beter quick idea on how to get these bits if abs_start.hour == 16: pldps = PlaylistDaypart.objects.filter( day=abs_start.weekday(), time_start__lte=datetime.time(17, 0), time_end__gte=datetime.time(20, 0), ) # very ugly. but no beter quick idea on how to get these bits if abs_start.hour >= 20: pldps = PlaylistDaypart.objects.filter( day=abs_start.weekday(), time_start__gte=datetime.time(20, 0), ) print 'matching dayparts:' for pldp in pldps: print pldp if slot_duration <= 3600: target_durations = [3600] else: target_durations = [3600, 7200] qs = Playlist.objects.filter( type='broadcast', broadcast_status=1, rotation=True, dayparts__in=pldps, target_duration__in=target_durations ) if self.user_ids: qs = qs.filter(user__pk__in=self.user_ids) # filling in slots while slot_time_left > 0: if slot_time_left <= 3600: qs = qs.filter(target_duration__in=[3600]) else: qs = qs.filter(target_duration__in=[3600, 7200]) #print 'excludes: %s' % self.used_playlist_ids qs = qs.exclude(pk__in=self.used_playlist_ids) print 'adding emission, have %s options' % qs.count() playlist = qs.order_by('?')[0] print '// random pick:' print 'slot_time_left: %s' % slot_time_left print 'slot_time_offset: %s' % slot_time_offset print playlist print playlist.target_duration print emission_start = (abs_start + datetime.timedelta(seconds=slot_time_offset)) theme = SCHEDULER_DEFAULT_THEME if abs_start.hour == 6: theme = 1 if abs_start.hour == 12: theme = 2 if abs_start.hour == 19: theme = 4 emission = Emission( content_object=playlist, time_start=emission_start, channel=self.channel, user=self.user, color=theme ) emission.save() # mark as used self.used_playlist_ids.append(playlist.id) slot_time_left -= playlist.target_duration # a bit redundant, i see slot_time_offset += playlist.target_duration
def schedule_object(request): log = logging.getLogger('abcast.schedulerviews.schedule_object') ct = request.POST.get('ct', None) obj_id = request.POST.get('obj_id', None) top = request.POST.get('top', None) left = request.POST.get('left', None) range_start = request.POST.get('range_start', None) range_end = request.POST.get('range_end', None) num_days = request.POST.get('num_days', SCHEDULER_NUM_DAYS) log.debug('content type: %s' % ct) if ct == 'playlist': obj = Playlist.objects.get(pk=int(obj_id)) log.debug('object to schedule: %s' % obj.name) pph = SCHEDULER_PPH # ppd = SCHEDULER_PPD ppd = (SCHEDULER_GRID_WIDTH - SCHEDULER_GRID_OFFSET) / int(num_days) top = float(top) / pph * 60 offset_min = int(15 * round(float(top)/15)) left = float(left) / ppd offset_d = int(round(float(left))) log.debug('minutes (offset): %s' % offset_min) log.debug('days (offset): %s' % offset_d) # calculate actual date/time for position schedule_start = datetime.datetime.strptime('%s 00:00' % range_start, '%Y-%m-%d %H:%M') # add offsets time_start = schedule_start + datetime.timedelta(minutes=offset_min) time_start = time_start + datetime.timedelta(days=offset_d) time_start = time_start + datetime.timedelta(hours=SCHEDULER_OFFSET) # time_end = time_start + datetime.timedelta(milliseconds=obj.get_duration()) # for duration calculation we use the 'target duration' (to avoid blocked slots) time_end = time_start + datetime.timedelta(seconds=(obj.target_duration)) log.debug('time_start: %s' % time_start) log.debug('time_end: %s' % time_end) # check if in past now = datetime.datetime.now() lock_end = now + datetime.timedelta(seconds=SCHEDULER_LOCK_AHEAD) if lock_end > time_start: return { 'message': _('You cannot schedule things in the past!') } # check if slot is free # hm just allow some seconds of tolerance (in case of mini-overlaps) es = Emission.objects.filter(time_end__gt=time_start + datetime.timedelta(seconds=2), time_start__lt=time_end) if es.count() > 0: for em in es: print 'Blocking emission: %s' % em.id print em.time_start print em.time_end return { 'message': _('Sorry, but the desired time does not seem to be available.') } # if no errors so far -> create emission and attach object e = Emission(content_object=obj, time_start=time_start, user=request.user) e.save() data = { 'status': True, 'obj_id': obj_id } return data
def add_emission(self, slot_start): from abcast.models import Channel, Emission from alibrary.models import Playlist log = logging.getLogger('abcast.autopilot.add_emission') log.debug('auto-adding emission, slot start: %s' % slot_start) # check if overlapping emission exists ces = Emission.objects.filter(time_start__lt=slot_start, time_end__gt=slot_start, channel=self.channel) print 'coliding emissions' print ces if ces.count() > 0: next_start = ces[0].time_end else: next_start = slot_start print 'next_start: %s' % next_start next_start = round_dt(next_start, 300) # round to 5 minutes print 'next_start rounded: %s' % next_start # check how much time is available until next emission fes = Emission.objects.filter(time_start__gte=next_start, channel=self.channel).order_by('time_start') print fes free_slot = 14400 if fes.count() > 0: log.debug('got %s emissions scheduled in future' % fes.count()) diff = fes[0].time_start - next_start free_slot = int(diff.total_seconds()) log.debug('length of free slot is: %s seconds' % free_slot) log.debug('length of free slot is: %s hours' % (int(free_slot) / 60 / 60)) if free_slot == 0 or free_slot < 60: print 'FREE SLOT IS %s. ENDS AT:' % free_slot print fes[0].time_end return fes[0].time_end """ look for possible playlists to schedule """ ps = Playlist.objects.filter(target_duration__lte=free_slot, rotation=True, status=1, type="broadcast", duration__gte=29*60*1000).order_by('?') if ps.count() > 0: p = ps[0] else: p = None print 'The random selection i!!' print p # create the scheduler entry if p: e = Emission(content_object=p, time_start=next_start, channel=self.channel, user=self.user, color=SCHEDULER_DEFAULT_THEME) e.save() # e, c = Emission.objects.get_or_create(content_object=p, time_start=next_start, channel=self.channel, user=self.user, color=SCHEDULER_DEFAULT_THEME) print 'Created emission, will run until: %s' % e.time_end return e.time_end
def schedule_object(request): log = logging.getLogger('abcast.schedulerviews.schedule_object') ct = request.POST.get('ct', None) obj_id = request.POST.get('obj_id', None) top = request.POST.get('top', None) left = request.POST.get('left', None) range_start = request.POST.get('range_start', None) range_end = request.POST.get('range_end', None) num_days = request.POST.get('num_days', SCHEDULER_NUM_DAYS) log.debug('content type: %s' % ct) if ct == 'playlist': obj = Playlist.objects.get(pk=int(obj_id)) log.debug('object to schedule: %s' % obj.name) pph = SCHEDULER_PPH # ppd = SCHEDULER_PPD ppd = (SCHEDULER_GRID_WIDTH - SCHEDULER_GRID_OFFSET) / int(num_days) top = float(top) / pph * 60 offset_min = int(15 * round(float(top) / 15)) left = float(left) / ppd offset_d = int(round(float(left))) log.debug('minutes (offset): %s' % offset_min) log.debug('days (offset): %s' % offset_d) # calculate actual date/time for position schedule_start = datetime.datetime.strptime('%s 00:00' % range_start, '%Y-%m-%d %H:%M') # add offsets time_start = schedule_start + datetime.timedelta(minutes=offset_min) time_start = time_start + datetime.timedelta(days=offset_d) time_start = time_start + datetime.timedelta(hours=SCHEDULER_OFFSET) time_end = time_start + datetime.timedelta(milliseconds=obj.get_duration()) log.debug('time_start: %s' % time_start) log.debug('time_end: %s' % time_end) # check if in past now = datetime.datetime.now() lock_end = now + datetime.timedelta(seconds=SCHEDULER_LOCK_AHEAD) if lock_end > time_start: return {'message': _('You cannot schedule things in the past!')} # check if slot is free es = Emission.objects.filter(time_end__gt=time_start, time_start__lt=time_end) if es.count() > 0: for em in es: print 'Blocking emission: %s' % em.id print em.time_start print em.time_end return { 'message': _('Sorry, but the desired time does not seem to be available.') } # if no errors so far -> create emission and attach object e = Emission(content_object=obj, time_start=time_start, user=request.user) e.save() data = {'status': True, 'obj_id': obj_id} return data