remove purecss in index.html, no line break between camera and broadcaster name, remove race condition in /chat causing http 500

このコミットが含まれているのは:
n9k 2021-05-16 00:24:50 +00:00
コミット 23c182b825
6個のファイルの変更71行の追加55行の削除

ファイルの表示

@ -232,6 +232,7 @@ class ConcatenatedSegments:
def _corrupt(self, n):
# TODO: make this corrupt more reliably (maybe it has to follow a full segment?)
# Doesn't corrupt when directly after init.mp4
print('ConcatenatedSegments._corrupt')
self.corrupt_hook()
self.close()
@ -242,4 +243,4 @@ class ConcatenatedSegments:
return b''
def close(self):
self._closed = True
self._closed = True

ファイルの表示

@ -12,6 +12,8 @@ import website.utils.stream as stream
from website.constants import DIR_STATIC, DIR_STATIC_EXTERNAL, VIDEOJS_ENABLED_BY_DEFAULT, SEGMENT_INIT, CHAT_SCROLLBACK, BROADCASTER_COLOUR, BROADCASTER_TOKEN, SEGMENTS_DIR, VIEW_COUNTING_PERIOD, HLS_TIME, NOTES, N_NONE, MESSAGE_MAX_LENGTH
from website.concatenate import ConcatenatedSegments, resolve_segment_offset
RE_WHITESPACE = re.compile(r'\s+')
viewers = viewership.viewers
def new_token():
@ -144,9 +146,10 @@ def chat_iframe():
viewership.made_request(token)
include_user_list = bool(request.args.get('users', default=1, type=int))
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)
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]
return render_template('chat-iframe.html',
token=token,
messages=messages,
@ -156,7 +159,9 @@ def chat_iframe():
broadcaster=token == BROADCASTER_TOKEN,
broadcaster_colour=BROADCASTER_COLOUR,
debug=request.args.get('debug'),
len=len)
RE_WHITESPACE=RE_WHITESPACE,
len=len,
chr=chr)
@current_app.route('/heartbeat')
def heartbeat():

ファイルの表示

@ -100,7 +100,7 @@
{% if message['viewer']['broadcaster'] %}
><span class="camera" title="Broadcaster">🎥</span
{% endif %}
><span class="name" style="color:#{{ message['viewer']['colour'].hex() }};">{{ message['viewer']['nickname'] or default_nickname(message['viewer']['token']) }}{% with tag = message['viewer']['nickname'] == None and not message['viewer']['broadcaster'] %}{% if tag %}<sup>{{ message['viewer']['tag'] }}</sup>{% endif %}</span
><span class="name" style="color:#{{ message['viewer']['colour'].hex() }};">{{ RE_WHITESPACE.sub(chr(160), message['viewer']['nickname'] or default_nickname(message['viewer']['token'])) }}{% with tag = message['viewer']['nickname'] == None and not message['viewer']['broadcaster'] %}{% if tag %}<sup>{{ message['viewer']['tag'] }}</sup>{% endif %}</span
{% if message['viewer']['tripcode']['string'] %}{% if tag %}><span style="margin-right:0.125em;"></span{% endif %}
><div class="tripcode" style="background-color:#{{ message['viewer']['tripcode']['background_colour'].hex() }};color:#{{ message['viewer']['tripcode']['foreground_colour'].hex() }};">{{ message['viewer']['tripcode']['string'] }}</div
{% endif %}{% endwith %}

ファイルの表示

@ -2,8 +2,6 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/static/external/pure-min.css" rel="stylesheet">
<link href="/static/external/grids-responsive-min.css" rel="stylesheet">
<link href="/static/platform.css" rel="stylesheet">
{% if use_videojs %}
<!-- https://unpkg.com/video.js@7.12.1/dist/video-js.min.css -->
@ -13,6 +11,19 @@
<!-- https://unpkg.com/@videojs/http-streaming@2.7.1/dist/videojs-http-streaming.min.js -->
<script src="/static/external/videojs-http-streaming.min.js"></script>
{% endif %}
<style>
.two-thirds, .one-third {
width: 100%;
}
@media screen and (min-width:48em) {
.two-thirds {
width: 66.6667%;
}
.one-third {
width: 33.3333%;
}
}
</style>
<noscript>
<style>
{% if use_videojs %}
@ -45,10 +56,9 @@
</style>
</noscript>
</head>
<body class="dark-theme">
<div class=pure-g>
<!-- TODO: get rid of PureCSS dependency here; the noscript block on top of the video is too large because the PureCSS files take longer to load -->
<div class="pure-u-1 pure-u-md-2-3">
<body class="dark-theme" style="margin:0;">
<div style="display:flex;flex-flow:row wrap;">
<div class="two-thirds">
<div id="stream">
{% if use_videojs %}
<input id="videojs-enabled" type="hidden" value="1">
@ -61,13 +71,13 @@
</noscript>
{% else %}
<input id="videojs-enabled" type="hidden" value="0">
<video controls autoplay src="{{ url_for('segments') }}?segment={{ start_number }}&amp;token={{ token }}">
<video controls autoplay src="{{ url_for('segments') }}?segment={{ start_number }}&amp;token={{ token }}"></video>
{% endif %}
</div>
<div id="stream-info-container"><noscript><iframe id="stream-info" src="{{ url_for('stream_info') }}?token={{ token }}&amp;embed=1"></iframe></noscript></div>
<div id="source" style="margin: -2.75em 0 1.5em 1.25em;"><a href="https://gitlab.com/ninya9k/onion-livestreaming" target="_blank">source code</a></div>
</div>
<div class="pure-u-1 pure-u-md-1-3">
<div class="one-third">
<div id="chat-border">
<!-- TODO: mobile tooltip -->
<input id="users-toggle" type="checkbox" style="display: none;">
@ -98,48 +108,47 @@
<div id="chat-container"><noscript><iframe id="chat" name="chat" src="{{ url_for('chat_iframe') }}?token={{ token }}&amp;users=0"></iframe></noscript></div>
<div id="users-container"><noscript><iframe name="users" src="{{ url_for('users', token=token) }}"></iframe></noscript></div>
</div>
<iframe style="height:98px;border-top:1px solid #434343;padding-top:0.5em;" src="{{ url_for('comment_iframe', token=token) }}"></iframe>
<iframe style="height:97px;border-top:1px solid #434343;padding-top:0.5em;" src="{{ url_for('comment_iframe', token=token) }}"></iframe>
</div>
</div>
</div>
</div>
<script>
function replaceFrameURL(frameContainerId, newUrl, newId, newName) {
const frameContainer = document.getElementById(frameContainerId);
const oldFrame = frameContainer.querySelector("*");
const newFrame = document.createElement("iframe");
newFrame.id = newId;
newFrame.name = newName;
newFrame.src = newUrl;
frameContainer.replaceChild(newFrame, oldFrame);
}
replaceFrameURL("stream-info-container", "{{ url_for('stream_info', token=token) }}", "stream-info", "");
replaceFrameURL("chat-container", "{{ url_for('chat_iframe', token=token) }}", "chat", "chat");
const chat = document.getElementById("chat");
const usersToggle = document.getElementById("users-toggle");
usersToggle.onchange = function() {
const chatMessages = chat.contentDocument.getElementById("messages");
const chatUsers = chat.contentDocument.getElementById("users");
if ( chatUsers == null || chatMessages == null )
return;
/* using display: none; resets css animations, i.e. the manual refresh banner */
if ( usersToggle.checked ) {
chatMessages.style.overflow = "hidden";
chatMessages.style.height = "0";
chatUsers.style.height = "unset";
chatUsers.style.overflow = "unset";
chat.style.transform = "revert";
} else {
chatUsers.style.overflow = "hidden";
chatUsers.style.height = "0";
chatMessages.style.height = "unset";
chatMessages.style.overflow = "unset";
chat.style.transform = null;
<script>
function replaceFrameURL(frameContainerId, newUrl, newId, newName) {
const frameContainer = document.getElementById(frameContainerId);
const oldFrame = frameContainer.querySelector("*");
const newFrame = document.createElement("iframe");
newFrame.id = newId;
newFrame.name = newName;
newFrame.src = newUrl;
frameContainer.replaceChild(newFrame, oldFrame);
}
}
chat.addEventListener("load", usersToggle.onchange);
</script>
<script src="/static/platform.js"></script>
replaceFrameURL("stream-info-container", "{{ url_for('stream_info', token=token) }}", "stream-info", "");
replaceFrameURL("chat-container", "{{ url_for('chat_iframe', token=token) }}", "chat", "chat");
const chat = document.getElementById("chat");
const usersToggle = document.getElementById("users-toggle");
usersToggle.onchange = function() {
const chatMessages = chat.contentDocument.getElementById("messages");
const chatUsers = chat.contentDocument.getElementById("users");
if ( chatUsers == null || chatMessages == null )
return;
/* using display: none; resets css animations, i.e. the manual refresh banner */
if ( usersToggle.checked ) {
chatMessages.style.overflow = "hidden";
chatMessages.style.height = "0";
chatUsers.style.height = "unset";
chatUsers.style.overflow = "unset";
chat.style.transform = "revert";
} else {
chatUsers.style.overflow = "hidden";
chatUsers.style.height = "0";
chatMessages.style.height = "unset";
chatMessages.style.overflow = "unset";
chat.style.transform = null;
}
}
chat.addEventListener("load", usersToggle.onchange);
</script>
<script src="/static/platform.js"></script>
</body>
</html>

ファイルの表示

@ -60,7 +60,7 @@
<div class="group">
<div class="group-name">Broadcaster</div>
<div class="person">
<span class="camera" title="Broadcaster">🎥</span><span class="name" style="color:#{{ person['colour'].hex() }};">{{ person['nickname'] or default_nickname(person['token']) }}</span>{% if person['tripcode']['string'] %}<div class="tripcode" style="background-color:#{{ person['tripcode']['background_colour'].hex() }};color:#{{ person['tripcode']['foreground_colour'].hex() }};">{{ person['tripcode']['string'] }}</div>{% endif %}
<span class="camera" title="Broadcaster">🎥</span>&NoBreak;<span class="name" style="color:#{{ person['colour'].hex() }};">{{ person['nickname'] or default_nickname(person['token']) }}</span>{% if person['tripcode']['string'] %}<div class="tripcode" style="background-color:#{{ person['tripcode']['background_colour'].hex() }};color:#{{ person['tripcode']['foreground_colour'].hex() }};">{{ person['tripcode']['string'] }}</div>{% endif %}
</div>
</div>
{% endif %}

ファイルの表示

@ -6,7 +6,7 @@ import website.utils.colour as colour
import website.utils.tripcode as tripcode
from website.constants import ANON_DEFAULT_NICKNAME, BROADCASTER_COLOUR, BROADCASTER_TOKEN, HLS_TIME, HOST_DEFAULT_NICKNAME, SEGMENTS_DIR, VIEW_COUNTING_PERIOD
viewers = {}
viewers = {} # TODO: remove viewers who haven't visited for a while, or limit the size of this dictionary somehow; otherwise this dictionary can become arbitrarily large
segment_views = {}
video_was_corrupted = set()
lock = threading.Lock()
@ -57,6 +57,7 @@ def made_request(token):
def view_segment(n, token=None, check_exists=True):
# n is None if segment_hook is called in ConcatenatedSegments and the current segment is init.mp4
if n == None:
print(f'init.mp4: {token}')
return
# technically this is a race condition