1 Commits

Author SHA1 Message Date
Klemek 4387f6da45 improv: colorblind colors 2021-07-14 00:06:00 +02:00
10 changed files with 49 additions and 140 deletions
-4
View File
@@ -1,4 +0,0 @@
DISCORD_TOKEN=
PYTHONPATH=./src
CRYPT_KEY=
LOG_DIR=logs
-46
View File
@@ -1,46 +0,0 @@
# About Analyst-bot's data usage
## TL;DR
Analyst-bot collects text message information. It does not share collected data with any third-party and data is retained 18 months or until the bot is leaving the guild/server.
## Data collection
Analyst-bot collects a Discord guild/server's history when asked to.
This includes:
- Visible text channel names
- Visible text messages: date and time of creation and edition, author, content, reactions and other available metadata (pinned, tts, etc.)
This does __not__ includes:
- Voice channels and not visible channels
- Not visible text messages
- Visible text messages' embedded content, images and other attachments
## Data processing
Any data collected is only processed in order to produce a one-time report sent to the user immediately. No temporary data are retained.
## Data storage and retain policy
Analyst-bot stores the collected data in files that are accessible by the software and its administrator only.
Any collected data are retained maximum 30 days until deletion or when the bot is leaving a guild/server.
## Data sharing
Analyst-bot does not share the data collected with any third-party.
## Right to retract
If you want to have your data removed, you can use the `%gdpr revoke` command or remove this bot from your guild/server.
## Terms agreement
By agreeing to these terms, you ensure having the legal age if you are in a country that does have one and you also ensure having the consent of every member involved.
*If you want more information, please contact the creator of this bot: <https://github.com/Klemek/discord-analyst>.*
Type `%gdpr agree` to agree to these terms, `%gdpr revoke` to remove this guild/server's collected data or `%gdpr` to see this message again.
+1 -4
View File
@@ -125,14 +125,11 @@ python3 src/main.py
## Changelog
* **v1.17**
* compliency with 30 days data keeping policy and data encryption
* improvements and bug fix
* **v1.16**
* `%freq graph` graph hours frequency along the week
* uses discord new time format
* `%freq` now shows quietest day of week and hour of day
* improvements and bug fix
* improvments and bug fix
* **v1.15**
* `nsfw:allow/only` filter nsfw channels
* `%find` can use regexes
+6 -6
View File
@@ -1,6 +1,6 @@
discord.py>=1.7.0
python-dotenv>=0.15.0
python-dateutil>=2.8.1
matplotlib>=3.4.2
cryptography>=2.8
git+git://github.com/Klemek/miniscord.git
discord.py==1.7.0
python-dotenv==0.15.0
python-dateutil==2.8.1
git+git://github.com/Klemek/miniscord.git
numpy
matplotlib
+19 -1
View File
@@ -2,6 +2,7 @@ from typing import List
from datetime import timedelta
import calendar
import matplotlib.pyplot as plt
import numpy as np
from io import BytesIO
import discord
import time
@@ -15,6 +16,18 @@ from utils import (
mention,
)
CB_color_cycle = [
"#e41a1c",
"#984ea3",
"#377eb8",
"#4daf4a",
"#dede00",
"#ff7f00",
"#a65628",
"#f781bf",
"#999999",
]
class Frequency:
def __init__(self):
@@ -58,7 +71,12 @@ class Frequency:
self.hours[i][0] * 7 / n_hours
]
ax.plot(
times, hours, label=calendar.day_name[i], linestyle="--", linewidth=0.8
times,
hours,
label=calendar.day_name[i],
linestyle="--",
linewidth=0.8,
c=CB_color_cycle[i],
)
hours = [day[hour] / n_hours for hour in range(24)] + [day[0] / n_hours]
+19 -49
View File
@@ -8,30 +8,28 @@ import time
import logging
import asyncio
import threading
from dotenv import load_dotenv
from cryptography.fernet import Fernet
from . import ChannelLogs
from utils import code_message, delta, deltas
LOG_DIR = "logs"
LOG_EXT = ".logz"
current_analysis = []
current_analysis_lock = threading.Lock()
ALREADY_RUNNING = -100
CANCELLED = -200
NO_FILE = -300
load_dotenv()
LOG_DIR = os.getenv("LOG_DIR", "logs")
LOG_EXT = os.getenv("LOG_EXT", ".logz")
CRYPT_KEY = os.getenv("CRYPT_KEY", "")
# 5 minutes, assume 'fast' arg
MIN_MODIFICATION_TIME = int(os.getenv("MAX_MODIFICATION_TIME", 5 * 60))
MIN_MODIFICATION_TIME = 5 * 60
# ~1 year, remove log file
MAX_MODIFICATION_TIME = 365 * 24 * 60 * 60
# 30 days, remove log file
MAX_MODIFICATION_TIME = int(os.getenv("MAX_MODIFICATION_TIME", 30 * 24 * 60 * 60))
class Worker:
def __init__(
@@ -131,41 +129,29 @@ class GuildLogs:
channels = {}
try:
last_time = os.path.getmtime(self.log_file)
encrypted_data = None
await code_message(progress, "Reading saved history (1/5)...")
gziped_data = None
await code_message(progress, "Reading saved history (1/4)...")
t0 = datetime.now()
with open(self.log_file, mode="rb") as f:
encrypted_data = f.read()
gziped_data = f.read()
logging.info(f"log {self.guild.id} > read in {delta(t0):,}ms")
if self.check_cancelled():
return CANCELLED, 0
await code_message(progress, "Reading saved history (2/5)...")
if CRYPT_KEY == "" or CRYPT_KEY is None:
gziped_data = encrypted_data
try:
t0 = datetime.now()
fernet = Fernet(CRYPT_KEY)
gziped_data = fernet.decrypt(encrypted_data)
logging.info(f"log {self.guild.id} > decrypted in {delta(t0):,}ms")
except:
gziped_data = encrypted_data
if self.check_cancelled():
return CANCELLED, 0
await code_message(progress, "Reading saved history (3/5)...")
await code_message(progress, "Reading saved history (2/4)...")
t0 = datetime.now()
json_data = gzip.decompress(gziped_data)
del gziped_data
logging.info(f"log {self.guild.id} > gzip decompress in {delta(t0):,}ms")
if self.check_cancelled():
return CANCELLED, 0
await code_message(progress, "Reading saved history (4/5)...")
await code_message(progress, "Reading saved history (3/4)...")
t0 = datetime.now()
channels = json.loads(json_data)
del json_data
logging.info(f"log {self.guild.id} > json parse in {delta(t0):,}ms")
if self.check_cancelled():
return CANCELLED, 0
await code_message(progress, "Reading saved history (5/5)...")
await code_message(progress, "Reading saved history (4/4)...")
t0 = datetime.now()
self.channels = {
int(id): ChannelLogs(channels[id], self) for id in channels
@@ -302,7 +288,7 @@ class GuildLogs:
return CANCELLED, 0
await code_message(
progress,
f"Saving history (1/4)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
f"Saving history (1/3)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
)
t0 = datetime.now()
json_data = bytes(json.dumps(self.dict()), "utf-8")
@@ -313,7 +299,7 @@ class GuildLogs:
return CANCELLED, 0
await code_message(
progress,
f"Saving history (2/4)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
f"Saving history (2/3)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
)
t0 = datetime.now()
gziped_data = gzip.compress(json_data)
@@ -325,28 +311,12 @@ class GuildLogs:
return CANCELLED, 0
await code_message(
progress,
f"Saving history (3/4)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
)
if CRYPT_KEY == "" or CRYPT_KEY is None:
encrypted_data = gziped_data
try:
t0 = datetime.now()
fernet = Fernet(CRYPT_KEY)
encrypted_data = fernet.encrypt(gziped_data)
logging.info(f"log {self.guild.id} > encrypted in {delta(t0):,}ms -> {len(gziped_data) / deltas(t0):,.3f} b/s")
except:
encrypted_data = gziped_data
if self.check_cancelled():
return CANCELLED, 0
await code_message(
progress,
f"Saving history (4/4)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
f"Saving history (3/3)...\n{real_total_msg:,} messages in {real_total_chan:,} channels",
)
t0 = datetime.now()
with open(self.log_file, mode="wb") as f:
f.write(encrypted_data)
f.write(gziped_data)
del gziped_data
del encrypted_data
logging.info(
f"log {self.guild.id} > saved in {delta(t0):,}ms -> {real_total_msg / deltas(t0):,.3f} m/s"
)
+1 -1
View File
@@ -18,7 +18,7 @@ emojis.load_emojis()
bot = Bot(
"Discord Analyst",
"1.17.0",
"1.16.1",
alias="%",
)
+2 -2
View File
@@ -69,8 +69,8 @@ class PresenceScanner(Scanner):
for mention in message.mentions:
pres.mention_others[mention] += 1
pres.messages[message.author] += 1
pres.channel_total[channel.id] += 1
pres.mention_count[message.author] += len(message.mentions)
pres.channel_total[channel.id] += 1
pres.mention_count[message.author] += len(message.mentions)
if len(raw_members) > 0:
for mention in message.mentions:
if mention in raw_members:
-26
View File
@@ -1,26 +0,0 @@
import os
import os.path
from dotenv import load_dotenv
from cryptography.fernet import Fernet
load_dotenv()
LOG_DIR = os.getenv("LOG_DIR", "logs")
LOG_EXT = os.getenv("LOG_DIR", ".logz")
CRYPT_KEY = os.getenv("CRYPT_KEY", "")
fernet = Fernet(CRYPT_KEY)
for item in os.listdir(LOG_DIR):
if item.endswith(LOG_EXT):
path = os.path.join(LOG_DIR, item)
data = None
with open(path, mode="rb") as f:
data = f.read()
try:
fernet.decrypt(data)
print(f"{item} already encrypted")
except:
with open(path, mode="wb") as f:
f.write(fernet.encrypt(data))
print(f"{item} was encrypted")
+1 -1
View File
@@ -27,7 +27,7 @@ This does __not__ includes:
Any data collected is only processed in order to produce a one-time report sent to the user immediately. No temporary data are retained.
**Data storage and retain policy**
Analyst-bot stores the collected data in files that are accessible by the software and its administrator only.
Any collected data are retained maximum 30 days until deletion or when the bot is leaving a guild/server.
Any collected data are retained maximum 18 months until deletion or when the bot is leaving a guild/server.
**Data sharing**
Analyst-bot does not share the data collected with any third-party.
**Right to retract**