14 Commits
Author SHA1 Message Date
lili 384ca03e23 rewrite space warning 2024-02-06 20:16:54 +01:00
lili 7722bdf608 add redeem name warning to init 2024-02-06 20:15:58 +01:00
lili 7dfc8faae7 add warning about spaces 2024-02-06 20:12:12 +01:00
lili 8e4d21c02f clarify positivity of integer 2024-02-06 19:11:53 +01:00
lili 571aa47aab make zero points not redeemable 2024-02-06 19:10:37 +01:00
lili 433564bddf only one debug log for terminal needed 2024-02-06 19:06:00 +01:00
lili 1abab80da4 promote to 1.2.2a1 2024-02-06 18:21:38 +01:00
lili 894ff175a6 remove redundant line ends 2024-02-06 18:18:15 +01:00
lili 6641121ca3 add <br>s to help message construction 2024-02-04 18:09:47 +01:00
lili 7ffb1a15b0 change webhook to use rawBody instead of body when reading msg
remove_emoji function is now unused, as shortcodes get scrubbed in rawBody now
2024-02-04 18:09:36 +01:00
lili e5e88bf520 Merge branch 'master' of github.com:SleepyLili/tlapbot into develop 2024-02-04 11:28:51 +01:00
lili b4a6c4e41c html/jinja formatting improvements
thanks chat
2024-02-03 18:47:42 +01:00
lili 8c19088640 readme: reword milestone "goal" and "price"
should hopefully suggest more clearly that milestones need goal
and everything else needs price
also changed the example to list goal first
2023-07-13 12:44:15 +02:00
lili 5316f7e205 improve default_redeems
list milestone "goal" first in the redeems dictionary
2023-07-13 12:42:46 +02:00
9 changed files with 81 additions and 61 deletions
+8 -8
View File
@@ -323,22 +323,22 @@ REDEEMS={
"lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."},
"react": {"price": 200, "type": "note", "info": "Attach link to a video for me to react to."},
"request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."},
"go_nap": {"type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000},
"go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."},
"inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]}
}
```
#### File format
`redeems.py` is a config file with just a `REDEEMS` key, that assigns a dictionary of redeems to it.
Each dictionary entry is a redeem, and the dictionary keys are strings that decides the chat command for the redeem.
The value is another dictionary that needs to have entries for `"type"`,
an entry for `"price"` unless the redeem is a milestone,
and optionally `"info"` and `"category"`.
If the `"type"` is `"milestone"`, there's an additional required `"goal"` field as well.
Each dictionary entry is a redeem, and the dictionary keys are strings that decide the chat command for the redeem.
The redeem names shouldn't have spaces in them.
The value is another dictionary that needs to have an entry for `"type"` and
an entry for `"price"` for non-milestones or `"goal"` for milestones.
Optionally, each redeem can also have `"info"` and `"category"` entries.
- `"price"` value should be an integer that decides how many points the redeem will cost. Milestone redeems don't use the `"price"` value.
- `"price"` value should be an integer that decides how many points the redeem will cost. Milestone redeems don't use the `"price"` value, they instead need to have a `"goal"`.
- `"goal"` is a required field for milestone goals. It should be an integer, deciding the amount of points required to complete the milestone.
- `"type"` value should be either `"list"`, `"counter"`, `"note"` or `"milestone"`. This decided the redeem's type, and whether it will show up as a counter at the top of the dashboard or as an entry in the "recent redeems" chart.
- `"info"` value should be a string that describes what the command does. It's optional, but I recommend writing one for all `"list"`, `"note"` and `"milestone"` redeems (so that chatters know what they're redeeming and whether they should leave a note).
- `"goal"` is a required field for milestone goals. It should be an integer, deciding the amount of points required to complete the milestone.
- `"category"` is an optional list of strings, the categories the redeem is in.
If a category from the list is in `ACTIVE_CATEGORIES` from `config.py`,
then the redeem will be active. It will not be active if none of the categories
+1 -1
View File
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup(
name='tlapbot',
version='1.2.1',
version='1.2.2a1',
packages=find_packages(),
include_package_data=True,
install_requires=[
+7
View File
@@ -35,6 +35,13 @@ def create_app(test_config=None):
if len(app.config['PREFIX']) != 1:
raise RuntimeError("Prefix is >1 character. "
"Change your config to set 1-character prefix.")
# Check for spaces in redeems (they won't work)
for redeem, _ in app.config['REDEEMS']:
if ' ' in redeem:
app.logger.warning(f"Redeem {redeem} has spaces in its name.")
app.logger.warning("Redeems with spaces are impossible to redeem.")
# prepare webhooks and redeem dashboard blueprints
from . import owncast_webhooks
+1 -1
View File
@@ -3,6 +3,6 @@ REDEEMS={
"lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."},
"react": {"price": 200, "type": "note", "info": "Attach link to a video for me to react to."},
"request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."},
"go_nap": {"type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000},
"go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."},
"inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]}
}
+9 -9
View File
@@ -4,20 +4,20 @@ from tlapbot.owncast_requests import send_chat
def send_help():
message = []
message.append("Tlapbot gives you points for being in chat, and then allows you to spend those points.\n")
message.append(f"People connected to chat receive {current_app.config['POINTS_AMOUNT_GIVEN']} points every {current_app.config['POINTS_CYCLE_TIME']} seconds.\n")
message.append("You can see your points and recent redeems in the Tlapbot dashboard. Look for a button to click under the stream window.\n")
message.append("""Tlapbot commands:
!help to see this help message.
!points to see your points.\n"""
message.append("Tlapbot gives you points for being in chat, and then allows you to spend those points. <br>")
message.append(f"People connected to chat receive {current_app.config['POINTS_AMOUNT_GIVEN']} points every {current_app.config['POINTS_CYCLE_TIME']} seconds. <br>")
message.append("You can see your points and recent redeems in the Tlapbot dashboard. Look for a button to click under the stream window. <br>")
message.append("""Tlapbot commands: <br>
!help to see this help message. <br>
!points to see your points. <br>"""
)
if current_app.config['LIST_REDEEMS']:
message.append("Active redeems:\n")
message.append("Active redeems: <br>")
for redeem, redeem_info in current_app.config['REDEEMS'].items():
if 'info' in redeem_info:
message.append(f"!{redeem} for {redeem_info['price']} points. {redeem_info['info']}\n")
message.append(f"!{redeem} for {redeem_info['price']} points. {redeem_info['info']} <br>")
else:
message.append(f"!{redeem} for {redeem_info['price']} points.\n")
message.append(f"!{redeem} for {redeem_info['price']} points. <br>")
else:
message.append("Check the dashboard for a list of currently active redeems.")
send_chat(''.join(message))
+1
View File
@@ -121,6 +121,7 @@ def remove_duplicate_usernames(db, user_id, username):
# # # misc. stuff # # #
# This is now unused since rawBody attribute of the webhook now returns cleaned-up emotes.
def remove_emoji(message):
return sub(
r'<img class="emoji" alt="(:.*?:)" title=":.*?:" src="/img/emoji/.*?">',
+6 -6
View File
@@ -36,22 +36,22 @@ def owncast_webhook():
user_id = data["eventData"]["user"]["id"]
display_name = data["eventData"]["user"]["displayName"]
current_app.logger.debug(f'New chat message from {display_name}:')
current_app.logger.debug(f'{data["eventData"]["body"]}')
if data["eventData"]["body"].startswith(f"{prefix}help"):
current_app.logger.debug(f'{data["eventData"]["rawBody"]}')
if data["eventData"]["rawBody"].startswith(f"{prefix}help"):
send_help()
elif data["eventData"]["body"].startswith(f"{prefix}points"):
elif data["eventData"]["rawBody"].startswith(f"{prefix}points"):
points = read_users_points(db, user_id)
if points is None:
send_chat("Error reading points.")
else:
send_chat(f"{display_name}'s points: {points}")
elif data["eventData"]["body"].startswith(f"{prefix}name_update"):
elif data["eventData"]["rawBody"].startswith(f"{prefix}name_update"):
# Forces name update in case bot didn't catch the NAME_CHANGE
# event. Also removes saved usernames from users with same name
# if user is authenticated.
change_display_name(db, user_id, display_name)
if data["eventData"]["user"]["authenticated"]:
remove_duplicate_usernames(db, user_id, display_name)
elif data["eventData"]["body"].startswith(prefix):
handle_redeem(data["eventData"]["body"], user_id)
elif data["eventData"]["rawBody"].startswith(prefix):
handle_redeem(data["eventData"]["rawBody"], user_id)
return data
+5 -3
View File
@@ -3,7 +3,7 @@ from tlapbot.db import get_db
from tlapbot.owncast_requests import send_chat
from tlapbot.redeems import (add_to_redeem_queue, add_to_counter, add_to_milestone,
check_apply_milestone_completion, milestone_complete, is_redeem_active)
from tlapbot.owncast_helpers import use_points, read_users_points, remove_emoji
from tlapbot.owncast_helpers import use_points, read_users_points
def handle_redeem(message, user_id):
@@ -32,9 +32,11 @@ def handle_redeem(message, user_id):
elif not note:
send_chat(f"Cannot redeem {redeem}, no amount of points specified.")
elif not note.isdigit():
send_chat(f"Cannot redeem {redeem}, amount of points is not an integer.")
send_chat(f"Cannot redeem {redeem}, amount of points is not a positive integer.")
elif int(note) > points:
send_chat(f"Can't redeem {redeem}, you're donating more points than you have.")
elif int(note) == 0:
send_chat(f"Can't donate zero points.")
elif add_to_milestone(db, user_id, redeem, int(note)):
send_chat(f"Succesfully donated to {redeem} milestone!")
if check_apply_milestone_completion(db, redeem):
@@ -64,7 +66,7 @@ def handle_redeem(message, user_id):
if not note:
send_chat(f"Cannot redeem {redeem}, no note included.")
return
if (add_to_redeem_queue(db, user_id, redeem, remove_emoji(note)) and
if (add_to_redeem_queue(db, user_id, redeem, note) and
use_points(db, user_id, price)):
send_chat(f"{redeem} redeemed for {price} points.")
else:
+43 -33
View File
@@ -30,12 +30,14 @@
<th>Your points balance</th>
</tr>
</thead>
{% for user in users %}
<tbody>
<td> {{ user[0] }} </td>
<td> {{ user[1] }} </td>
</tbody>
{% for user in users %}
<tr>
<td> {{ user[0] }} </td>
<td> {{ user[1] }} </td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
@@ -52,12 +54,14 @@
<th>Active counters</th>
</tr>
</thead>
{% for counter in counters %}
<tbody>
<td> {{ counter[0] }} </td>
<td> {{ counter[1] }} </td>
</tbody>
{% for counter in counters %}
<tr>
<td> {{ counter[0] }} </td>
<td> {{ counter[1] }} </td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if milestones %}
@@ -68,13 +72,15 @@
<th>Progress</th>
</tr>
</thead>
{% for milestone in milestones %}
<tbody>
<td> {{ milestone[0] }} </td>
<td> <progress id="file" max={{ milestone[2] }} value={{ milestone[1] }}></progress></td>
<td> {{ milestone[1] }} / {{ milestone[2] }}</td>
</tbody>
{% for milestone in milestones %}
<tr>
<td> {{ milestone[0] }} </td>
<td> <progress id="file" max={{ milestone[2] }} value={{ milestone[1] }}></progress></td>
<td> {{ milestone[1] }} / {{ milestone[2] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endif %}
@@ -99,16 +105,18 @@
<th>Note</th>
</tr>
</thead>
{% for row in queue %}
<tbody>
<td>{{ row[0].replace(tzinfo=utc_timezone).astimezone().strftime("%H:%M") }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[3] }}</td>
{% if row[2] %}
<td>{{ row[2] }}</td>
{% endif %}
</tbody>
{% for row in queue %}
<tr>
<td>{{ row[0].replace(tzinfo=utc_timezone).astimezone().strftime("%H:%M") }}</td>
<td>{{ row[1] }}</td>
<td>{{ row[3] }}</td>
{% if row[2] %}
<td>{{ row[2] }}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</body>
@@ -136,20 +144,22 @@
<th>Description</th>
</tr>
</thead>
{% for redeem, redeem_info in redeems.items() %}
<tbody>
<td>{{ prefix }}{{ redeem }}</td>
{% if redeem_info["type"] == "milestone" %}
<td></td>
{% else %}
<td>{{ redeem_info["price"] }}</td>
{% endif %}
<td>{{ redeem_info["type"] }}</td>
{% if redeem_info["info"] %}
<td>{{ redeem_info["info"] }}</td>
{% endif %}
</tbody>
{% for redeem, redeem_info in redeems.items() %}
<tr>
<td>{{ prefix }}{{ redeem }}</td>
{% if redeem_info["type"] == "milestone" %}
<td></td>
{% else %}
<td>{{ redeem_info["price"] }}</td>
{% endif %}
<td>{{ redeem_info["type"] }}</td>
{% if redeem_info["info"] %}
<td>{{ redeem_info["info"] }}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</body>