Compare commits
6
Commits
v1.2.1
...
6641121ca3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6641121ca3 | ||
|
|
7ffb1a15b0 | ||
|
|
e5e88bf520 | ||
|
|
b4a6c4e41c | ||
|
|
8c19088640 | ||
|
|
5316f7e205 |
@@ -323,22 +323,21 @@ 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.
|
||||
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
|
||||
|
||||
@@ -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"]}
|
||||
}
|
||||
@@ -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> \n")
|
||||
message.append(f"People connected to chat receive {current_app.config['POINTS_AMOUNT_GIVEN']} points every {current_app.config['POINTS_CYCLE_TIME']} seconds. <br> \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. <br> \n")
|
||||
message.append("""Tlapbot commands: <br>
|
||||
!help to see this help message. <br>
|
||||
!points to see your points. <br> \n"""
|
||||
)
|
||||
if current_app.config['LIST_REDEEMS']:
|
||||
message.append("Active redeems:\n")
|
||||
message.append("Active redeems: <br> \n")
|
||||
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> \n")
|
||||
else:
|
||||
message.append(f"!{redeem} for {redeem_info['price']} points.\n")
|
||||
message.append(f"!{redeem} for {redeem_info['price']} points. <br> \n")
|
||||
else:
|
||||
message.append("Check the dashboard for a list of currently active redeems.")
|
||||
send_chat(''.join(message))
|
||||
|
||||
@@ -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/.*?">',
|
||||
|
||||
@@ -36,22 +36,23 @@ 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"]["rawBody"]}')
|
||||
current_app.logger.debug(f'{data["eventData"]["body"]}')
|
||||
if data["eventData"]["body"].startswith(f"{prefix}help"):
|
||||
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
|
||||
|
||||
@@ -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):
|
||||
@@ -64,7 +64,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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user