Пример #1
0
def main():
    from mcserverstats import logalyzer
    logs = logalyzer.LogDirectory('test_logs/')
    timeline_data = get_timeline_data(logs, None, None)
    t_start, t_end = timeline_data[:2]
    title = '%s to %s' % (timeutils.human_date_str(timeutils.epoch_to_date_str(t_start)),
                          timeutils.human_date_str(timeutils.epoch_to_date_str(t_end)) or 'last activity')

    draw_timeline(timeline_data, 'test.png', title)
    write_timeline_html_page(timeline_data, 'test.html', title)
Пример #2
0
 def test_epoch_to_date_str(self):
     self.assertEqual('2015-03-12 00:00:00', timeutils.epoch_to_date_str(1426114800))
     self.assertEqual('2015-03-12 00:00:09', timeutils.epoch_to_date_str(1426114809))
     self.assertEqual('2015-03-12 01:10:01', timeutils.epoch_to_date_str(1426119001))
Пример #3
0
def get_timeline_html(timeline_data, title='', hour_width=30, html_style_players=default_html_style_players):
    t_start, t_end, lines, uptimes = timeline_data
    hour_width = int(hour_width)

    sec_per_hour = 3600
    sec_to_screen = lambda t: t * hour_width / sec_per_hour

    template_session = '<span style="left:%(start).3fpx;width:%(duration).3fpx"></span>'
    def session_to_html(t_from, t_to):
        start = sec_to_screen(t_from - t_start)
        duration = sec_to_screen(t_to - t_from)
        return template_session % {
            'start': start, 'duration': duration - 4,
        }

    template_player_sessions = \
        '<tr><td class="tl_sessions tl_user_%(name)s">' \
        '%(sessions)s' \
        '</td><td><img height="16px" src="%(head_b64)s"/>&nbsp;%(name)s</td></tr>'
    html_all_player_sessions = []
    for line in lines:
        last_name = line[-1][-1]
        html_sessions = ''
        for uuid, t_from, t_to, name in line:
            html_sessions += session_to_html(t_from, t_to)
        html_all_player_sessions.append(template_player_sessions % {
            'name': last_name,
            'sessions': html_sessions,
            'head_b64': player_head_img_base64(last_name),
        })
    html_all_player_sessions = ''.join(html_all_player_sessions)

    html_uptimes = ''.join(session_to_html(t_from, t_to) for t_from, t_to in uptimes)

    html_hours = []
    bg_offset = None
    for sec in range((t_start // sec_per_hour) * sec_per_hour,
                     t_end + sec_per_hour, sec_per_hour):
        if sec <= t_start or sec >= t_end:
            continue  # out of range by rounding
        if bg_offset is None:  # first drawn hour
            bg_offset = sec_to_screen(sec - t_start)
        hour_text = timeutils.epoch_to_date_str(sec, '%k')  # hour 0-23, space padded
        html_hours.append('<span>%s</span>' % hour_text)
    html_hours = ''.join(html_hours)

    page_data = {
        'title_text': title,
        'hour_width': hour_width,
        'bg_scale_b64': bg_scale_base64(hour_width),
        'bg_offset': bg_offset,
        'hour_offset': bg_offset - hour_width/2,
        'sessions_width': sec_to_screen(t_end - t_start),
        'style_players': html_style_players,
        'hours': html_hours,
        'uptimes': html_uptimes,
        'players': html_all_player_sessions,
    }
    template_timeline = \
        '<style type="text/css">' \
        '.timeline td{margin:0px;padding:0px}' \
        '.timeline span{display:inline-block;overflow:hidden}' \
        '.tl_hours span{width:%(hour_width)ipx;text-align:center}' \
        '.tl_uptimes,.tl_sessions{background-image:url(%(bg_scale_b64)s);background-position:%(bg_offset).3fpx 0px;background-repeat:repeat;position:relative;height:20px}' \
        '.tl_uptimes span,.tl_sessions span{background-color:rgba(128,128,128,0.3);border:2px solid rgba(0,0,0,0.4);height:12px;position:absolute;top:2px;' \
        'border-radius:8px;-moz-border-radius:8px}' \
        '.tl_uptimes span{background-color:#0f0;border-color:black;height:6px;top:5px}' \
        '%(style_players)s' \
        '</style><table class="timeline" style="border-collapse:collapse">' \
        '<tr><td class="tl_hours" style="min-width:%(sessions_width).3fpx;padding-left:%(hour_offset).3fpx">' \
        '%(hours)s' \
        '</td><td>Hours</td></tr>' \
        '<tr><td class="tl_uptimes">' \
        '%(uptimes)s' \
        '</td><td>Server&nbsp;online</td></tr>' \
        '%(players)s' \
        '<tr><td colspan=2 align="center" class="tl_title" style="font-size:20px">%(title_text)s</td></tr>' \
        '</table>'
    return template_timeline % page_data
Пример #4
0
def draw_timeline(timeline_data, img_path, title='', im_width=None, settings=default_settings, **kwargs):
    """
    /-----border------\
    | |||||scale||||| |
    | ||line_border|| |
    | ----uptimes---- |
    | ||line_border|| |
    | /-name_border-\ |
    | | NAME ====== | |
    | \-name_border-/ |
    |   line_border   |
    | (===)    (====) |
    |   line_border   |
    | (==========)    |
    | ||line_border|| |
    |---title_border--|
    |     [TITLE]     |
    \-----border------/
    """
    for key in kwargs:
        settings[key] = kwargs[key]
    s = SettingsDict(**settings)

    t_start, t_end, lines, uptimes = timeline_data
    if not im_width:
        im_width = int((t_end - t_start) / 3600 * s.scale_gap)  # TODO

    # calculate sizes
    title_box_height = s.title_height + s.title_border \
        if len(title) > 0 and s.title_height > 0 else 0
    scale_box_height = s.scale_height + 2 * s.line_border \
        if s.scale_height > 0 else 0
    line_height = 2 * s.name_border + s.name_height
    line_box_height = s.line_border + line_height
    im_height = 2 * s.border \
                + title_box_height + scale_box_height + s.uptimes_height + s.line_border \
                + line_box_height * (len(lines) - 1) + line_height
    inner_width = im_width - 2 * s.border
    h_stretch = inner_width / (t_end - t_start)
    s.name_radius = min(s.name_radius, s.name_height / 2 + s.name_border)
    name_horiz_border = max(s.name_border, s.name_radius)

    # start drawing
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, im_width, im_height)
    c = cairo.Context(surface)
    c.select_font_face(s.font_name)
    c.set_source_rgba(*s.bg_color)
    c.paint()

    # draw title
    c.set_font_size(s.title_height)
    draw_text(c, title, s.title_color, s.border, im_height - (s.border + s.title_height / 2), CENTER,
              im_width - s.border, shadow=(s.title_shadow_color, s.title_shadow_offset))

    # draw scale
    c.set_source_rgba(*s.scale_color)
    c.set_line_width(s.scale_line_width)
    c.set_font_size(s.scale_height)
    scale_line_y = s.border + s.scale_height
    scale_line_dy = line_box_height * len(lines) + s.line_border * 2 + s.uptimes_height
    for sec in range((t_start // 3600) * 3600, t_end + 3600, 3600):
        if sec < t_start or sec > t_end:
            continue  # out of range by rounding
        hour_text = timeutils.epoch_to_date_str(sec, '%k')  # hour 0-23, space padded
        if hour_text == ' 0': c.set_line_width(s.scale_line_width_midnight)
        elif hour_text == '12': c.set_line_width(s.scale_line_width_noon)
        scale_line_x = int(s.border + (sec - t_start) * h_stretch) - c.get_line_width() / 2
        c.move_to(scale_line_x, scale_line_y)
        c.rel_line_to(0, scale_line_dy)
        c.stroke()
        if hour_text in (' 0', '12'): c.set_line_width(s.scale_line_width)
        # TODO rotate by 90 degrees
        draw_text(c, hour_text, s.scale_color, scale_line_x, s.border + s.scale_height / 2,
                  CENTER, None, shadow=(s.scale_shadow_color, s.scale_shadow_offset))

    # draw uptimes
    for t_from, t_to in uptimes:
        x = s.border + (t_from - t_start) * h_stretch
        w = (t_to - t_from) * h_stretch
        draw_rounded_rect(c, s.uptimes_color, x, scale_box_height,
                          w, s.uptimes_height,
                          s.uptimes_height, (2, 0,0,0))

    # draw sessions
    y_offset = s.border + scale_box_height + s.uptimes_height
    c.set_font_size(s.name_height)
    for i, line in enumerate(lines):
        y = i * line_box_height + y_offset
        for session in line:
            uuid, t_from, t_to, name = session
            color = s.color_from_uuid(uuid, settings)
            x = s.border + (t_from - t_start) * h_stretch
            w = (t_to - t_from) * h_stretch
            draw_rounded_rect(c, color, x, y, w, line_height, s.name_radius, dark_border(2, color))
            t_x = x + name_horiz_border
            h_y = y + s.name_border
            t_y = h_y + s.name_height / 2
            if w > s.name_height + 2 * s.name_border:
                draw_head(c, t_x, h_y, s.name_height, name)
            draw_text(c, name, s.name_color, t_x, t_y, max_w=w - 2 * name_horiz_border,
                      shadow=(s.name_shadow_color, s.name_shadow_offset))

    # save image
    surface.write_to_png(img_path)