示例#1
0
def chat_iframe():
    token = get_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)

    include_user_list = bool(request.args.get('users', default=1, type=int))
    with viewership.lock:  # required because another thread can change chat.messages while we're iterating through it
        messages = (message for message in chat.messages
                    if not message['hidden'])
        messages = zip(
            messages,
            range(CHAT_SCROLLBACK))  # show at most CHAT_SCROLLBACK messages
        messages = [message for message, _ in messages]

    chat.decorate(messages)
    return render_template('chat-iframe.html',
                           token=token,
                           messages=messages,
                           include_user_list=include_user_list,
                           people=viewership.get_people_list(),
                           default_nickname=viewership.default_nickname,
                           broadcaster=token == BROADCASTER_TOKEN,
                           broadcaster_colour=BROADCASTER_COLOUR,
                           background_colour=BACKGROUND_COLOUR,
                           stream_title=stream.get_title(),
                           stream_viewers=viewership.count(),
                           stream_uptime=stream.readable_uptime(),
                           debug=request.args.get('debug'),
                           RE_WHITESPACE=RE_WHITESPACE,
                           len=len,
                           chr=chr)
示例#2
0
def comment_iframe(token=None):
    token = token or get_token() or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)

    try:
        preset = viewership.preset_comment_iframe.pop(token)
    except KeyError:
        preset = {}

    # a new captcha was requested; fill in the message that the user has typed so far
    if preset == {} and request.method == 'POST':
        message = request.form.get('message', '')
        if len(message) < MESSAGE_MAX_LENGTH:
            preset['message'] = message

    captcha = chat.get_captcha(token)

    response = render_template('comment-iframe.html',
                               token=token,
                               captcha=captcha,
                               nonce=chat.new_nonce(),
                               note=NOTES[preset.get('note', N_NONE)],
                               message=preset.get('message', ''),
                               default=viewership.default_nickname(token),
                               nickname=viewers[token]['nickname'],
                               viewer=viewers[token],
                               show_settings=preset.get(
                                   'show_settings', False))
    response = make_response(response)
    response.set_cookie('token', token)
    return response
示例#3
0
def third_party(fn):
    token = get_token()
    if not viewership.is_allowed(token):
        return abort(403)

    response = send_from_directory(DIR_STATIC_EXTERNAL, fn, add_etags=False)
    response.headers['Cache-Control'] = 'public, max-age=604800, immutable'
    response.expires = response.date + datetime.timedelta(days=7)
    return response
示例#4
0
def _static(fn):
    token = get_token()
    if fn != 'eye.png' and not viewership.is_allowed(token):
        return abort(403)

    response = send_from_directory(DIR_STATIC, fn, add_etags=False)
    if fn == 'radial.apng':
        response.mimetype = 'image/png'
        response.headers[
            'Cache-Control'] = 'no-store'  # caching this in any way messes with the animation
    elif response.status_code == 200 and not fn.endswith('.png'):
        response.headers['Cache-Control'] = 'no-cache'
    return response
示例#5
0
def settings():
    token = get_token(form=True) or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)

    nickname = request.form.get('nickname', '')
    password = request.form.get('password', '')

    old_nickname = viewers[token]['nickname']
    old_tripcode = viewers[token]['tripcode']

    note, ok = chat.set_nickname(nickname, token)
    if ok:
        if request.form.get('remove-tripcode'):
            note, _ = chat.remove_tripcode(token)
        elif request.form.get('set-tripcode'):
            note, _ = chat.set_tripcode(password, token)

    if not viewership.is_allowed(token):
        if request.form.get('confirm'):
            return redirect(url_for('index'))
        viewers[token]['nickname'] = old_nickname
        viewers[token]['tripcode'] = old_tripcode
        viewership.preset_comment_iframe[token] = {
            'note': N_NONE,
            'show_settings': True
        }
        return render_template('comment-confirm-iframe.html',
                               token=token,
                               nickname=old_nickname
                               or viewership.default_nickname(token))

    viewership.preset_comment_iframe[token] = {
        'note': note,
        'show_settings': True
    }
    return redirect(url_for('comment_iframe', token=token))
示例#6
0
def users():
    token = get_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)
    return render_template('users-iframe.html',
                           token=token,
                           people=viewership.get_people_list(),
                           default_nickname=viewership.default_nickname,
                           broadcaster=token == BROADCASTER_TOKEN,
                           debug=request.args.get('debug'),
                           broadcaster_colour=BROADCASTER_COLOUR,
                           background_colour=BACKGROUND_COLOUR,
                           len=len)
示例#7
0
def segment_init():
    token = get_token() or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)
    try:
        viewership.video_was_corrupted.remove(token)
    except KeyError:
        pass
    if not stream.is_online():
        return abort(404)

    response = send_from_directory(SEGMENTS_DIR, f'init.mp4', add_etags=False)
    response.headers['Cache-Control'] = 'no-cache'
    response.set_cookie('token', token)
    return response
示例#8
0
def segments():
    token = get_token() or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)
    try:
        viewership.video_was_corrupted.remove(token)
    except KeyError:
        pass
    if not stream.is_online():
        return abort(404)

    def should_close_connection():
        if not stream.is_online():
            return True
        if not viewership.is_allowed(token):
            return True
        return False

    start_number = request.args.get('segment', type=int)
    if start_number == None:
        start_number = resolve_segment_offset()
    try:
        concatenated_segments = ConcatenatedSegments(
            start_number=start_number,
            token=token,
            segment_hook=lambda n: viewership.view_segment(
                n, token, check_exists=False),
            corrupt_hook=lambda: viewership.video_was_corrupted.add(token
                                                                    ),  # lock?
            should_close_connection=should_close_connection)
    except FileNotFoundError:
        return abort(404)

    def generate():
        while True:
            chunk = concatenated_segments.read(8192)
            if chunk == b'':
                return
            yield chunk

    response = current_app.response_class(generate(), mimetype='video/mp4')
    response.headers['Cache-Control'] = 'no-store'
    response.set_cookie('token', token)
    return response
示例#9
0
def playlist():
    token = get_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)
    try:
        viewership.video_was_corrupted.remove(token)
    except KeyError:
        pass
    if not stream.is_online():
        return abort(404)

    try:
        token_playlist = stream.token_playlist(token)
    except FileNotFoundError:
        return abort(404)
    response = make_response(token_playlist)
    response.mimetype = 'application/x-mpegURL'
    response.headers['Cache-Control'] = 'no-cache'
    return response
示例#10
0
def comment():
    token = get_token(form=True) or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)

    nonce = request.form.get('nonce')
    message = request.form.get('message', '').replace('\r',
                                                      '').replace('\n',
                                                                  ' ').strip()
    c_response = request.form.get('captcha')
    c_ciphertext = request.form.get('captcha-ciphertext')

    failure_reason = chat.comment(message, token, c_response, c_ciphertext,
                                  nonce)

    viewership.preset_comment_iframe[token] = {
        'note': failure_reason,
        'message': message if failure_reason else ''
    }
    return comment_iframe(token=token)
示例#11
0
def heartbeat():
    token = get_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)
    online = stream.is_online()
    start_abs, start_rel = stream.get_start(absolute=True, relative=True)

    response = {
        'viewers': viewership.count(),
        'online': online,
        'current_segment': stream.current_segment(),
        'title': stream.get_title(),
        'start_abs': start_abs if online else None,
        'start_rel': start_rel if online else None
    }
    # commented out because we should be able to tell if we're not receiving the stream already
    #    if token in viewership.video_was_corrupted:
    #        response['corrupted'] = True

    return response
示例#12
0
def segment_arbitrary(n):
    token = get_token()
    if not viewership.is_allowed(token):
        return abort(403)
    try:
        viewership.video_was_corrupted.remove(token)
    except KeyError:
        pass
    if not stream.is_online():
        return abort(404)

    # only send segments that are listed in stream.m3u8
    # this stops old segments from previous streams being sent
    if f'stream{n}.m4s' not in stream.get_segments():
        return abort(404)
    viewership.view_segment(n, token)
    response = send_from_directory(SEGMENTS_DIR,
                                   f'stream{n}.m4s',
                                   add_etags=False)
    response.headers['Cache-Control'] = 'no-cache'
    return response
示例#13
0
def stream_info():
    token = get_token() or new_token()
    viewership.made_request(token)
    if not viewership.is_allowed(token):
        return abort(403)

    embed_images = bool(request.args.get('embed', type=int))

    start_abs, start_rel = stream.get_start(absolute=True, relative=True)
    online = stream.is_online()
    return render_template(
        'stream-info-iframe.html',
        title=stream.get_title(),
        viewer_count=viewership.count(),
        stream_start_abs_json=json.dumps(start_abs if online else None),
        stream_start_rel_json=json.dumps(start_rel if online else None),
        stream_uptime=start_rel if online else None,
        online=online,
        video_was_corrupted=token != None
        and token in viewership.video_was_corrupted,
        embed_images=embed_images,
        token=token,
        broadcaster_colour=BROADCASTER_COLOUR)
示例#14
0
def index(token=None):
    token = token or get_token() or new_token()
    viewership.made_request(token)
    if request.method == 'POST':
        password = request.form.get('password', '')
        chat.set_tripcode(password, token)
    if not viewership.is_allowed(token):
        response = render_template('secret-club.html',
                                   token=token,
                                   tripcode=viewers[token]['tripcode'])
        response = make_response(response, 403)
        response.set_cookie('token', token)
        return response
    try:
        viewership.video_was_corrupted.remove(token)
    except KeyError:
        pass

    use_videojs = bool(
        request.args.get('videojs',
                         default=int(VIDEOJS_ENABLED_BY_DEFAULT),
                         type=int))
    online = stream.is_online()

    response = render_template(
        'index.html',
        token=token,
        use_videojs=use_videojs,
        online=online,
        start_number=resolve_segment_offset() if online else 0,
        hls_time=CONFIG['stream']['hls_time'])
    response = make_response(
        response
    )  # TODO: add a view of the chat only, either as an arg here or another route
    response.set_cookie('token', token)
    return response
示例#15
0
 def should_close_connection():
     if not stream.is_online():
         return True
     if not viewership.is_allowed(token):
         return True
     return False