1
0
Fork 0
mirror of https://github.com/myned/watcher.git synced 2024-11-01 12:22:38 +00:00

Initial upload

This commit is contained in:
Myned 2022-06-08 20:59:15 -05:00
parent 1d80bfeaad
commit 4b5b047203
No known key found for this signature in database
GPG key ID: 33790F979F7A28B8
7 changed files with 250 additions and 4 deletions

40
.gitignore vendored
View file

@ -1,3 +1,6 @@
# CUSTOM
config.toml
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
@ -20,7 +23,6 @@ parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
@ -50,6 +52,7 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
@ -72,6 +75,7 @@ instance/
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
@ -82,7 +86,9 @@ profile_default/
ipython_config.py
# pyenv
.python-version
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
@ -91,7 +97,22 @@ ipython_config.py
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
@ -127,3 +148,16 @@ dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

View file

@ -1,2 +1,77 @@
# Watcher
Discord bot for inactive roles
An experimental [Hikari](https://www.hikari-py.dev) Discord bot for assigning active and inactive roles based on member activity
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/B0B1AUB66)
## Prerequisites
A Unix-based operating system is used for the following commands\
[WSL](https://docs.microsoft.com/en-us/windows/wsl) can be used to run Linux on Windows, but is not required to run the bot
## Requirements
[Git](https://git-scm.com/downloads)\
[Python](https://www.python.org) 3.10+\
[Poetry](https://python-poetry.org/docs/master)
## Installing
Clone this repository
```
git clone https://github.com/Myned/Watcher.git
```
Go to the project folder
```
cd Watcher
```
Create a virtual environment and install dependencies
```
poetry install
```
## Usage
Go to the project folder
```
cd Watcher
```
Run with optimizations
```
poetry run python -OO run.py
```
## Setup
Run to create `config.toml`\
The file will automatically generate if it does not exist
```
client = 0 # bot application id
token = "" # bot token
activity = "you" # bot status
db = "watcher.db" # sqlite3 db filepath
guild = 0 # guild id to watch
active = 0 # active role id
inactive = 0 # inactive role id
duration = 0 # time in seconds before considered inactive
```
## Updating
Go to the project folder
```
cd Watcher
```
Pull changes from the repository
```
git pull
```
Update the virtual environment
```
poetry update
```
## Uninstalling
Remove the project folder
```
rm -rf Watcher
```
## Contributing
1. [Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) this repository on GitHub
2. Make changes to the code
3. Format the code with [Black](https://black.readthedocs.io/en/stable) inside the project folder
```
poetry run python black .
```
4. [Commit](https://github.com/git-guides/git-commit) the changes to the fork
5. Create a [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) from the fork
## Credits
[hikari](https://github.com/hikari-py/hikari)\
[hikari-lightbulb](https://github.com/tandemdude/hikari-lightbulb)

27
config.py Normal file
View file

@ -0,0 +1,27 @@
import toml
import hikari
# Hikari activity type
# https://www.hikari-py.dev/hikari/presences.html#hikari.presences.ActivityType
ACTIVITY = hikari.ActivityType.WATCHING
# Default bot configuration
CONFIG = """\
client = 0 # bot application id
token = "" # bot token
activity = "you" # bot status
db = "watcher.db" # sqlite3 db filepath
guild = 0 # guild id to watch
active = 0 # active role id
inactive = 0 # inactive role id
duration = 0 # time in seconds before considered inactive
"""
# Load or create config.toml
try:
config = toml.load("config.toml")
except FileNotFoundError:
with open("config.toml", "w") as f:
f.write(CONFIG)
print("config.toml created with default values. Restart when modified")
exit()

2
poetry.toml Normal file
View file

@ -0,0 +1,2 @@
[virtualenvs]
in-project = true

24
pyproject.toml Normal file
View file

@ -0,0 +1,24 @@
[tool.poetry]
name = "watcher"
version = "0.1.0"
description = "Watcher Discord Bot"
authors = ["Myned <dev@myned.dev>"]
license = "MIT"
[tool.poetry.dependencies]
python = "~3.10"
toml = "*"
uvloop = "*"
sqlitedict = "*"
hikari = {extras = ["speedups"], version = "*"}
hikari-lightbulb = "*"
[tool.poetry.dev-dependencies]
black = "*"
[tool.black]
line-length = 120
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

32
run.py Normal file
View file

@ -0,0 +1,32 @@
import os
import hikari
import lightbulb
from lightbulb.ext import tasks
import config as c
# Unix optimizations
# https://github.com/hikari-py/hikari#uvloop
if os.name != "nt":
import uvloop
uvloop.install()
bot = lightbulb.BotApp(token=c.config["token"], intents=hikari.Intents.ALL_GUILDS)
# Listener for global exceptions
@bot.listen(hikari.ExceptionEvent)
async def on_error(event):
exception = event.exception.__cause__ or event.exception
await (await bot.rest.fetch_application()).owner.send(f"```❗ {type(exception).__name__}: {exception}```")
raise event.exception
tasks.load(bot)
bot.load_extensions_from("tasks")
bot.run(activity=hikari.Activity(name=c.config["activity"], type=c.ACTIVITY) if c.config["activity"] else None)

52
tasks/activity.py Normal file
View file

@ -0,0 +1,52 @@
import datetime as dt
import sqlitedict
import hikari
import lightbulb
from lightbulb.ext import tasks
import config as c
plugin = lightbulb.Plugin("activity")
db = sqlitedict.SqliteDict(c.config["db"], tablename=str(c.config["guild"]), autocommit=True)
# Check every minute if inactive
@tasks.task(s=60)
async def check_activity():
for author_id, timestamp in db.items():
if dt.datetime.now(dt.timezone.utc) - timestamp >= dt.timedelta(seconds=c.config["duration"]):
member = plugin.bot.cache.get_member(c.config["guild"], author_id)
if c.config["active"] and c.config["active"] in member.role_ids:
await member.remove_role(c.config["active"])
if c.config["inactive"] and c.config["inactive"] not in member.role_ids:
await member.add_role(c.config["inactive"])
# Listener for bot ready
@plugin.listener(hikari.StartedEvent)
async def on_ready(event):
check_activity.start()
# Listener for guild messages
@plugin.listener(hikari.GuildMessageCreateEvent)
async def on_message(event):
if event.is_bot or event.guild_id != c.config["guild"]:
return
db[event.author_id] = event.message.timestamp # or datetime.datetime.utcnow()
if c.config["active"] and c.config["active"] not in event.member.role_ids:
await event.member.add_role(c.config["active"])
if c.config["inactive"] and c.config["inactive"] in event.member.role_ids:
await event.member.remove_role(c.config["inactive"])
def load(bot):
bot.add_plugin(plugin)
def unload(bot):
bot.remove_plugin(plugin)