Merge branch 'dev'

このコミットが含まれているのは:
n9k 2022-06-29 04:32:35 +00:00
コミット 322dc9b361
16個のファイルの変更38行の追加28行の削除

ファイルの表示

@ -32,31 +32,21 @@ on chat, e.g. text-to-speech or Twitch Plays Pokémon.
View events like this: View events like this:
```sh ```sh
socat UNIX-CONNECT:event.sock STDOUT socat -u UNIX-CONNECT:event.sock STDOUT
``` ```
Sidenote, this will still read from stdin, and if you send anything on
stdin the event socket will close itself. If you want to ignore stdin,
I couldn't figure out how to get `socat` to do it so you can do it like
this:
```sh
cat > /dev/null | socat UNIX-CONNECT:event.sock STDOUT
```
If you do this `cat` will not exit when the connection is closed so you
will probably have to interrupt it with `^C`.
#### Examples #### Examples
If you have `jq` you can view prettified events like this: If you have `jq` you can view prettified events like this:
```sh ```sh
socat UNIX-CONNECT:event.sock STDOUT | jq socat -u UNIX-CONNECT:event.sock STDOUT | jq
``` ```
(On older versions of `jq` you have to say `jq .` when reading from (On older versions of `jq` you have to say `jq .` when reading from
stdin.) stdin.)
Use this to get each new chat message on a new line: Use this to get each new chat message on a new line:
```sh ```sh
socat UNIX-CONNECT:event.sock STDOUT | jq 'select(.type == "message") | .event.nomarkup' socat -u UNIX-CONNECT:event.sock STDOUT | jq 'select(.type == "message") | .event.nomarkup'
``` ```
##### Text-to-speech ##### Text-to-speech
@ -65,7 +55,7 @@ This command will take each new chat message with the prefix "!say ",
strip the prefix, and synthesize the rest of the message as speech using strip the prefix, and synthesize the rest of the message as speech using
`espeak`: `espeak`:
```sh ```sh
socat UNIX-CONNECT:event.sock STDOUT \ socat -u UNIX-CONNECT:event.sock STDOUT \
| jq --unbuffered 'select(.type == "message") | .event.nomarkup' \ | jq --unbuffered 'select(.type == "message") | .event.nomarkup' \
| grep -E --line-buffered '^"!say ' \ | grep -E --line-buffered '^"!say ' \
| sed -Eu 's/^"!say /"/' \ | sed -Eu 's/^"!say /"/' \

ファイルの表示

@ -75,7 +75,7 @@ def create_app(toml_config):
from anonstream.events import start_event_server_at from anonstream.events import start_event_server_at
async def start_event_server(): async def start_event_server():
return await start_event_server_at( return await start_event_server_at(
app.config['SOCKET_EVENT_ADDRESS'] app.config['SOCKET_EVENT_ADDRESS']
) )
app.add_background_task(start_event_server) app.add_background_task(start_event_server)

ファイルの表示

@ -31,7 +31,7 @@ class ArgsSeqs(Args):
async def cmd_chat_help(): async def cmd_chat_help():
normal = ['chat', 'help'] normal = ['chat', 'help']
response = ( response = (
'Usage: chat {show [MESSAGES] | delete SEQS}\n' 'Usage: chat delete SEQS\n'
'Commands:\n' 'Commands:\n'
#' chat show [MESSAGES]......show chat messages\n' #' chat show [MESSAGES]......show chat messages\n'
' chat delete SEQS..........delete chat messages\n' ' chat delete SEQS..........delete chat messages\n'

ファイルの表示

@ -23,7 +23,8 @@ def generate_token_hash_and_tag(token):
return token_hash, tag return token_hash, tag
def generate_user( def generate_user(
timestamp, token, broadcaster, verified=False, presence=Presence.NOTWATCHING, timestamp, token, broadcaster,
verified=False, presence=Presence.NOTWATCHING, headers=None,
): ):
colour = generate_colour( colour = generate_colour(
seed='name\0' + token, seed='name\0' + token,
@ -54,6 +55,7 @@ def generate_user(
'total': 0, 'total': 0,
'current': {}, 'current': {},
}, },
'headers': headers,
} }
def get_default_name(user): def get_default_name(user):

ファイルの表示

@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2022 n9k <https://git.076.ne.jp/ninya9k> # SPDX-FileCopyrightText: 2022 n9k <https://git.076.ne.jp/ninya9k>
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
import anonstream.routes.errors import anonstream.routes.error
import anonstream.routes.core import anonstream.routes.core
import anonstream.routes.websocket import anonstream.routes.websocket
import anonstream.routes.nojs import anonstream.routes.nojs

ファイルの表示

@ -47,7 +47,7 @@ async def stream(timestamp, user):
raise NotFound('The stream is offline.') raise NotFound('The stream is offline.')
else: else:
try: try:
eyes_id = create_eyes(user, dict(request.headers)) eyes_id = create_eyes(user, tuple(request.headers))
except RatelimitedEyes as e: except RatelimitedEyes as e:
retry_after, *_ = e.args retry_after, *_ = e.args
error = TooManyRequests( error = TooManyRequests(

ファイルの表示

@ -151,7 +151,7 @@ async def nojs_submit_message(timestamp, user):
else: else:
state_id = None state_id = None
if message_was_added: if message_was_added:
deverify(user) deverify(user, timestamp=timestamp)
url = url_for( url = url_for(
'nojs_chat_form', 'nojs_chat_form',

ファイルの表示

@ -72,7 +72,7 @@ def auth_required(f):
return wrapper return wrapper
def generate_and_add_user( def generate_and_add_user(
timestamp, token=None, broadcaster=False, verified=False, timestamp, token=None, broadcaster=False, verified=False, headers=None,
): ):
token = token or generate_token() token = token or generate_token()
user = generate_user( user = generate_user(
@ -80,6 +80,7 @@ def generate_and_add_user(
token=token, token=token,
broadcaster=broadcaster, broadcaster=broadcaster,
verified=verified, verified=verified,
headers=headers,
) )
USERS_BY_TOKEN[token] = user USERS_BY_TOKEN[token] = user
USERS_UPDATE_BUFFER.add(token) USERS_UPDATE_BUFFER.add(token)
@ -132,6 +133,7 @@ def with_user_from(context, fallback_to_token=False):
if CONFIG['ACCESS_CAPTCHA'] and not broadcaster: if CONFIG['ACCESS_CAPTCHA'] and not broadcaster:
if user is not None: if user is not None:
user['last']['seen'] = timestamp user['last']['seen'] = timestamp
user['headers'] = tuple(context.headers)
response = await f(timestamp, user, *args, **kwargs) response = await f(timestamp, user, *args, **kwargs)
elif fallback_to_token: elif fallback_to_token:
#assert not broadcaster #assert not broadcaster
@ -146,8 +148,14 @@ def with_user_from(context, fallback_to_token=False):
else: else:
if user is not None: if user is not None:
user['last']['seen'] = timestamp user['last']['seen'] = timestamp
user['headers'] = tuple(context.headers)
else: else:
user = generate_and_add_user(timestamp, token, broadcaster) user = generate_and_add_user(
timestamp,
token,
broadcaster,
headers=tuple(context.headers),
)
response = await f(timestamp, user, *args, **kwargs) response = await f(timestamp, user, *args, **kwargs)
# Set cookie # Set cookie

ファイルの表示

@ -851,6 +851,7 @@ const connect_websocket = () => {
} }
chat_live_ball.style.borderColor = "gold"; chat_live_ball.style.borderColor = "gold";
chat_live_status.innerHTML = "<span data-verbose='true'>Connecting to chat...</span><span data-verbose='false'>&middot;&middot;&middot;</span>"; chat_live_status.innerHTML = "<span data-verbose='true'>Connecting to chat...</span><span data-verbose='false'>&middot;&middot;&middot;</span>";
ws = null;
ws = new WebSocket(`ws://${document.domain}:${location.port}/live?token=${encodeURIComponent(TOKEN)}`); ws = new WebSocket(`ws://${document.domain}:${location.port}/live?token=${encodeURIComponent(TOKEN)}`);
ws.addEventListener("open", (event) => { ws.addEventListener("open", (event) => {
console.log("websocket open", event); console.log("websocket open", event);

ファイルの表示

@ -9,7 +9,7 @@ from quart import current_app, websocket
from anonstream.broadcast import broadcast, broadcast_users_update from anonstream.broadcast import broadcast, broadcast_users_update
from anonstream.stream import is_online, get_stream_title, get_stream_uptime_and_viewership from anonstream.stream import is_online, get_stream_title, get_stream_uptime_and_viewership
from anonstream.user import get_sunsettable_users from anonstream.user import get_absent_users, get_sunsettable_users, deverify
from anonstream.wrappers import with_timestamp from anonstream.wrappers import with_timestamp
CONFIG = current_app.config CONFIG = current_app.config
@ -64,6 +64,12 @@ async def t_sunset_users(timestamp, iteration):
if iteration == 0: if iteration == 0:
return return
# Deverify absent users
for user in get_absent_users(timestamp):
deverify(user, timestamp=timestamp)
# Remove as many absent users as possible
# Broadcast a users update, in case any users being # Broadcast a users update, in case any users being
# removed have been mutated or are new. # removed have been mutated or are new.
broadcast_users_update() broadcast_users_update()

ファイルの表示

@ -2,6 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-security-policy" content="default-src 'none'; img-src 'self'; style-src 'nonce-{{ csp }}';"> <meta http-equiv="content-security-policy" content="default-src 'none'; img-src 'self'; style-src 'nonce-{{ csp }}';">
<style nonce="{{ csp }}"> <style nonce="{{ csp }}">
body { body {

ファイルの表示

@ -2,6 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ error.code }} {{ error.name }}</title> <title>{{ error.code }} {{ error.name }}</title>
<style> <style>
body { body {
@ -9,7 +10,7 @@
color: #ddd; color: #ddd;
font-family: sans-serif; font-family: sans-serif;
font-size: 14pt; font-size: 14pt;
margin: 4pt 6pt; margin: 3pt 6pt;
text-align: center; text-align: center;
text-shadow: 2px 0px 1px orangered; text-shadow: 2px 0px 1px orangered;
} }

ファイルの表示

@ -173,8 +173,9 @@ def verify(user, digest, answer):
return verification_happened return verification_happened
@with_timestamp() def deverify(user, timestamp=None):
def deverify(timestamp, user): if timestamp is None:
timestamp = get_timestamp()
if user['verified'] and not user['broadcaster']: if user['verified'] and not user['broadcaster']:
n_user_messages = 0 n_user_messages = 0
for message in reversed(MESSAGES): for message in reversed(MESSAGES):

ファイルの表示

@ -122,7 +122,7 @@ def handle_inbound_message(timestamp, queue, user, nonce, comment, digest, answe
else: else:
notice = None notice = None
if message_was_added: if message_was_added:
deverify(user) deverify(user, timestamp=timestamp)
return { return {
'type': 'ack', 'type': 'ack',
'nonce': nonce, 'nonce': nonce,

ファイルの表示

@ -75,7 +75,7 @@ threshold = 20
[flood.video] [flood.video]
max_eyes = 3 max_eyes = 3
cooldown = 12.0 cooldown = 12.0
expire_after = 5.0 expire_after = 10.0
overwrite = true overwrite = true
[presence] [presence]