コード例 #1
0
ファイル: schedule.py プロジェクト: rmcauley/rainwave
def manage_next(sid):
    # pylint: disable=W0612
    max_sched_id, max_elec_id, num_elections, max_future_time = _get_schedule_stats(sid)
    # pylint: enable=W0612
    now_producer = get_producer_at_time(sid, timestamp())
    next_producer = get_producer_at_time(sid, max_future_time)
    nextnext_producer_start = db.c.fetch_var(
        "SELECT sched_start FROM r4_schedule WHERE sid = %s AND sched_used = FALSE AND sched_start > %s AND sched_timed = TRUE",
        (sid, max_future_time),
    )
    time_to_future_producer = None
    if nextnext_producer_start:
        time_to_future_producer = nextnext_producer_start - max_future_time
    else:
        time_to_future_producer = 86400
    while len(upnext[sid]) < min(now_producer.plan_ahead_limit, next_producer.plan_ahead_limit):
        target_length = None
        if time < 20:
            log.debug("timing", "SID %s <20 seconds to upnext event, not using timing." % sid)
        if time_to_future_producer < 40:
            target_length = time_to_future_producer
            next_producer = rainwave.events.shortest_election.ShortestElectionProducer(sid)
            log.debug("timing", "SID %s <40 seconds to upnext event, using shortest elections." % sid)
        elif time_to_future_producer < (playlist.get_average_song_length(sid) * 1.3):
            target_length = time_to_future_producer
            log.debug("timing", "SID %s close to event, timing to %s seconds long." % (sid, target_length))
        elif time_to_future_producer < (playlist.get_average_song_length(sid) * 2.2):
            target_length = playlist.get_average_song_length(sid)
            log.debug("timing", "SID %s has an upcoming event, timing to %s seconds long." % (sid, target_length))
        next_event = next_producer.load_next_event(target_length, max_elec_id)
        if not next_event:
            log.info(
                "manage_next",
                "Producer ID %s type %s did not produce an event." % (next_producer.id, next_producer.type),
            )
            next_producer = election.ElectionProducer(sid)
            next_event = next_producer.load_next_event(target_length, max_elec_id)
        upnext[sid].append(next_event)
        if next_event.is_election:
            num_elections += 1
        if next_event.is_election and next_event.id > max_elec_id:
            max_elec_id = next_event.id
        max_future_time += upnext[sid][-1].length()
        time_to_future_producer -= upnext[sid][-1].length()
        next_producer = get_producer_at_time(sid, max_future_time)

    future_time = None
    if current[sid].start:
        future_time = current[sid].start + current[sid].length()
    else:
        future_time = int(timestamp() + current[sid].length())
    for evt in upnext[sid]:
        evt.start = future_time
        future_time += evt.length()
        if evt.is_election:
            evt.update_vote_counts()
コード例 #2
0
ファイル: schedule.py プロジェクト: Reani/rainwave
def _create_elections(sid):
	# Step, er, 0: Update the request cache first, so elections have the most recent data to work with
	# (the entire requests module depends on its caches)
	request.update_cache(sid)

	max_sched_id, max_elec_id, num_elections = _get_schedule_stats(sid)
	log.debug("create_elec", "Max sched ID: %s // Max elec ID: %s // Num elections already existing: %s // Size of next: %s" % (max_sched_id, max_elec_id, num_elections, len(next[sid])))

	# Step 2: Load up any elections that have been added while we've been idle and append them to the list
	unused_elec_id = db.c.fetch_list("SELECT elec_id FROM r4_elections WHERE sid = %s AND elec_id > %s AND elec_used = FALSE AND elec_priority = FALSE ORDER BY elec_id", (sid, max_elec_id))
	unused_elecs = []
	for elec_id in unused_elec_id:
		unused_elecs.append(event.Election.load_by_id(elec_id))

	# Step 3: Insert elections where there's time and adjust predicted start times as necessary, if num_elections < 2 then create them where necessary
	i = 1
	running_time = current[sid].start_actual + current[sid].length()
	if len(next[sid]) > 0:
		next[sid][0].start = running_time
	while i < len(next[sid]):
		next_start = next[sid][i].start
		gap = next_start - running_time
		next_elec_i = None
		next_elec_length = playlist.get_average_song_length(sid)
		j = i
		while j < len(next[sid]):
			if next[sid][j].is_election:
				next_elec = j
				next_elec_length = next[sid][j].length()
				break
		if not next_elec_i and len(unused_elecs) > 0:
			next_elec_length = unused_elecs[0].length()

		# TODO: This algorithm DEFINITELY needs code/concept review
		# There are potential holes - it is not as comprehensive a scheduler as the previous
		# Rainwave scheduler, however it is vastly simplified.
		# One drawback is that you cannot schedule elections themselves to run at certain times.

		create_elecs = False
		# If the event we're looking at collides with the previous event, adjust this event to start later
		if gap <= 0:
			next[sid][i].start = running_time
			running_time += next[sid][i].length()
		# If we have no elections current in the next list and there's enough time to fit a song, stuff an election in
		# (this automatically takes into account unused elections, based on next_elec_length definition above)
		elif not next_elec_i and gap <= (next_elec_length * 1.4):
			next_elec = None
			# If we have an existing unused election, we can use that (as next_elec_length is already based on the first unused elec, this can happen)
			if len(unused_elecs) > 0:
				next_elec = unused_elecs.pop(0)
			# If not, create a new election timed to the gap (next_elec_length will be the average song length*1.4, so this will happen frequently)
			else:
				next_elec = _create_election(sid, running_time, gap)
			num_elections += 1
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].insert(i, next_elec)
		# If it's more accurate to squeeze a created election in here than adjust the next event, move the event
		# *OR* the next event is too far out and we have elections in hand
		elif next_elec_i and ((gap <= (next_elec_length / 2)) or (gap > (next_elec_length * 1.5))):
			next_elec = next[sid].pop(next_elec_i)
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].insert(i, next_elec)
		# The next event is better off aligned
		else:
			next[sid][i].start = running_time
			running_time += next[sid][i].length()
		i += 1

	needed_elecs = config.get_station(sid, "num_planned_elections") - num_elections
	log.debug("create_elec", "Before: Needed elecs: %s // Unused elecs: %s // Current num elections: %s // Next size: %s" % (needed_elecs, len(unused_elecs), num_elections, len(next[sid])))
	# Step 5: If we're at less than X elections available, create them (or use unused ones) and append them
	# No timing is required here, since we're simply outright appending to the end
	# (any elections appearing before a scheduled item would be handled by the block above)
	failures = 0
	while needed_elecs > 0 and failures <= 2:
		next_elec = None
		if len(unused_elecs) > 0:
			next_elec = unused_elecs.pop(0)
		else:
			next_elec = _create_election(sid, running_time)
		next_elec_length = next_elec.length()
		if next_elec_length > 0:
			next_elec.start = running_time
			running_time += next_elec.length()
			next[sid].append(next_elec)
			num_elections += 1
			needed_elecs -= 1
		else:
			log.error("create_elec", "Election ID %s was faulty - zero length.  Deleting.")
			next_elec.delete()
			failures += 1
	if failures >= 2:
		log.error("create_elec", "Total failure when creating elections.")
	log.debug("create_elec", "After: Unused elecs: %s // Current num elections: %s // Next size: %s" % (len(unused_elecs), num_elections, len(next[sid])))