Added following functionalities

- Emojis can be ignored
- If note length is higher than max length only the first five emojis/reactions will be printed
- It is possible to change how the note is presented.
This commit is contained in:
Fotoente 2022-03-13 09:31:58 +01:00
parent 9402ce3c28
commit d506ea627d
6 changed files with 159 additions and 46 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
emojicount.cfg emojicount.cfg
miceco.cfg miceco.cfg
roboduck.cfg

View file

@ -13,7 +13,8 @@ Edit the file `example-miceco.cfg` (see table below) and save it as `miceco.cfg`
Install following Python packages via `pip install` Install following Python packages via `pip install`
``` ```
emoji emoji
python-dateutil configparser
requests
``` ```
or use `pip install -r requirements.txt` in the cloned folder or use `pip install -r requirements.txt` in the cloned folder
@ -25,17 +26,27 @@ In your console type `crontab -e`
Add `0 9 * * * python3 /path/to/file/miceco.py > /path/to/file/miceco_output.txt` Add `0 9 * * * python3 /path/to/file/miceco.py > /path/to/file/miceco_output.txt`
The script will now be run every day on 9:00am server time. The script will now be run every day on 9:00am server time.
### Available flags
There are two flags that can be used to specify which external files the script gonna use
| Flag | Long name | controlled behaviour |
|------|-------------|------------------------------------------------------------------------------------------|
| `-c` | `--config` | What configuration file should be used.<br/>Without this flag `miceco.cfg` will be used. |
| `-i` | `--ignored` | Which emojis should be ignored.<br/> Without this `ignoredemojis.txt` will be used |
### Options for the config file ### Options for the config file
|Name|Values|Explanation| | Name | Values | Explanation |
|----|----|----| |----------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|instance|domain.tld|The domain name for your Misskey instance that you want to read the notes from. Only supply the domain name and TLD, no `/`,`:` or `https` | instance | domain.tld | The domain name for your Misskey instance that you want to read the notes from. Only supply the domain name and TLD, no `/`,`:` or `https` |
|user|`username`|The user you want to read the notes from| | user | `username` | The user you want to read the notes from |
|token|`String`|The token for your bot. Needs permission to write notes| | token | `String` | The token for your bot. Needs permission to write notes |
|getReaction|`Boolean`|Should reactions emojis be counted as well? `True` or `False`| | getReaction | `Boolean` | Should reactions emojis be counted as well? `True` or `False` |
| ignoreEmojis | `Boolean` | Should Emojis that are specified in `ignoredemojis.txt` be ignored? `True`or `False` | |
| noteVisibility | `String` | How should the note be shown in the Timeline? `public`: Visible for everyone<br/>`folowers`: only visible for your followers<br/>`specified`: Only you can see it |
### Other notes ### Other notes
The script is written in a way that only the notes and reactions from yesterday(!!!) are caught and counted. There is no option currently to specify the date range for collection. The script is written in a way that only the notes and reactions from yesterday(!!!) are caught and counted. There is no option currently to specify the date range for collection.
The exact timestamp to get yesterday is determined by the timezone of your server. At the moment there is no way to change the timezone. The exact timestamp to get yesterday is determined by the timezone of your server. At the moment there is no way to change the timezone.
#### Feel free to open a feature request or issue if you want something changed! If the note is longer than the maximum note length of the instance, then only the five most used emojis (and five most used reactions) will be shown.

View file

@ -3,3 +3,5 @@ instance=//DOMAIN.TLD//
user=//USERNAME// user=//USERNAME//
token=//TOKEN HERE// token=//TOKEN HERE//
getReaction=True getReaction=True
ignoreEmojis=true
noteVisibility=public

15
ignoredemojis.txt Normal file
View file

@ -0,0 +1,15 @@
🟩
🟨
🟪
👹
🪄
🪙
🔸
🎉
🇩🇪
↙️
➡️

153
miceco.py
View file

@ -2,11 +2,11 @@ import configparser
import os import os
import re import re
import sys import sys
import argparse
from datetime import * from datetime import *
# import dateutil.relativedelta
import requests import requests
import emoji as emojilib import emoji as emojilib
# TODO: Replace with emojis library!
def check_str_to_bool(input_text) -> bool: def check_str_to_bool(input_text) -> bool:
@ -27,7 +27,15 @@ doubleList = []
text = "" text = ""
getReactions = False getReactions = False
configfilePath = os.path.join(os.path.dirname(__file__), 'miceco.cfg') parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", help="location of the configuration file")
parser.add_argument("-i", "--ignored", help="location of the file which emojis are ignored while counting")
args = parser.parse_args()
if args.config is None:
configfilePath = os.path.join(os.path.dirname(__file__), 'miceco.cfg')
else:
configfilePath = args.config
if not os.path.exists(configfilePath): if not os.path.exists(configfilePath):
print("No config File found!") print("No config File found!")
@ -47,6 +55,33 @@ try:
except (TypeError, ValueError) as err: except (TypeError, ValueError) as err:
getReactions = False getReactions = False
try:
ignoreEmojis = check_str_to_bool(config.get("misskey", "ignoreEmojis"))
except (TypeError, ValueError) as err:
ignoreEmojis = False
if ignoreEmojis:
if args.ignored is None:
ignored_path = os.path.join(os.path.dirname(__file__), "ignoredemojis.txt")
else:
ignored_path = args.ignored
if not os.path.exists(ignored_path):
print("No file for ignored emojis found!")
print("Setting skipped!")
if os.path.exists(ignored_path):
with open(ignored_path, "r", encoding="utf8") as ignored_file:
ignored_emojis = []
for element in ignored_file.readlines():
i = element.strip()
ignored_emojis.append(emojilib.demojize(i))
noteVisibility = config.get("misskey", "noteVisibility") # How should the note be printed?
if noteVisibility != "public" and noteVisibility != "home" and noteVisibility != "followers" and noteVisibility != \
"specified":
noteVisibility = "followers"
try: try:
req = requests.post(url + "/users/show", json={"username": user, "host": None, "i": token}) req = requests.post(url + "/users/show", json={"username": user, "host": None, "i": token})
req.raise_for_status() req.raise_for_status()
@ -55,12 +90,24 @@ except requests.exceptions.HTTPError as err:
sys.exit(1) sys.exit(1)
userid = req.json()["id"] userid = req.json()["id"]
nickname = req.json()["name"] if req.json()["name"] is not None: # If no nickname is set, just user the username instead
nickname = req.json()["name"]
else:
nickname = req.json()["username"]
# Get max note length
try:
req = requests.post(url + "/meta", json={"detail": True, "i": token})
req.raise_for_status()
except requests.exceptions.HTTPError as err:
print("Couldn't get maximal note length!\n" + str(err))
print("Setting max note length to 3.000 characters")
max_note_length = 3000
max_note_length = int(req.json()["maxNoteTextLength"])
today = date.today() today = date.today()
formerDate = today - timedelta(days=1) formerDate = today - timedelta(days=1)
# formerDate = today - timedelta(weeks=1) #Last week
# formerDate = today - dateutil.relativedelta.relativedelta(months=1)
formerDateMidnight = datetime.combine(formerDate, time(0, 0, 0)) formerDateMidnight = datetime.combine(formerDate, time(0, 0, 0))
todayMidnight = datetime.combine(today, time(0, 0, 0)) todayMidnight = datetime.combine(today, time(0, 0, 0))
@ -93,12 +140,11 @@ while True:
sys.exit(1) sys.exit(1)
for jsonObj in req.json(): for jsonObj in req.json():
# textDict = jsonObj
noteList.append(jsonObj) noteList.append(jsonObj)
formerTimestamp = lastTimestamp formerTimestamp = lastTimestamp
if not len(noteList) <= 1: # If there is one or less notes, then break the while loop if not len(noteList) <= 0: # If there is zero notes, then break the while loop
lastTime = noteList[len(noteList) - 1]["createdAt"] lastTime = noteList[len(noteList) - 1]["createdAt"]
lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z')) * 1000) lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z')) * 1000)
else: else:
@ -119,17 +165,17 @@ for element in noteList:
if emojis is not None: if emojis is not None:
for emoji in emojis: for emoji in emojis:
if emoji["name"].find( if emoji["name"].find("@") == -1: # Only emojis from the own instance, because reactions will be in
"@") == -1: # Only emojis from the own instance, because reactions will be in "emojis" # "emojis" too
# too emojiname = ":" + emoji["name"] + ":"
if not emoji["name"] in doubleList: if emojiname not in doubleList:
doubleList.append(emoji["name"]) # Easy way to prevent a double emoji in the list. doubleList.append(emojiname) # Easy way to prevent a double emoji in the list.
emojiDict = {"emoji": ":" + emoji["name"] + ":", "count": 0} emojiDict = {"emoji": emojiname, "count": 0}
emojiList.append(emojiDict) emojiList.append(emojiDict)
else: else:
continue continue
index = doubleList.index(emoji["name"]) index = doubleList.index(":" + emoji["name"] + ":")
emojiList[index]["count"] += element["text"].count(emojiList[index]["emoji"]) emojiList[index]["count"] += element["text"].count(emojiList[index]["emoji"])
@ -142,19 +188,29 @@ for element in noteList:
UTF8text = element["text"] + " " + element["cw"] UTF8text = element["text"] + " " + element["cw"]
else: else:
UTF8text = element["text"] UTF8text = element["text"]
UTF8List = re.findall(emojilib.get_emoji_regexp(), UTF8text) # Find all UTF8 Emojis in Text and CW text UTF8ListRaw = re.findall(emojilib.get_emoji_regexp(), UTF8text) # Find all UTF8 Emojis in Text and CW text
UTF8text = emojilib.demojize(UTF8text)
if len(UTF8List) > 0: # TODO urgent! replace "get_emoji_regexp"
UTF8List = list(set(UTF8List)) if len(UTF8ListRaw) > 0:
UTF8List = list(set(UTF8ListRaw))
for emoji in UTF8List: for emoji in UTF8List:
emoji = emojilib.demojize(emoji)
if emoji not in doubleList: if emoji not in doubleList:
doubleList.append(emoji) # Easy way to prevent a double emoji in the list. doubleList.append(emoji) # Easy way to prevent a double emoji in the list without checking the whole
# dictionary
emojiDict = {"emoji": emoji, "count": 0} emojiDict = {"emoji": emoji, "count": 0}
emojiList.append(emojiDict) emojiList.append(emojiDict)
index = doubleList.index(emoji) index = doubleList.index(emoji)
emojiList[index]["count"] += UTF8text.count(emoji) emojiList[index]["count"] += UTF8text.count(emoji)
if ignoreEmojis:
for ignoredEmoji in ignored_emojis:
if ignoredEmoji in doubleList:
indx = doubleList.index(ignoredEmoji)
del doubleList[indx]
del emojiList[indx]
doubleList = [] doubleList = []
emojiList = sorted(emojiList, reverse=True, key=lambda d: d["count"]) # Sort it by the most used Emojis! emojiList = sorted(emojiList, reverse=True, key=lambda d: d["count"]) # Sort it by the most used Emojis!
@ -185,7 +241,7 @@ if getReactions:
reactionList.append(jsonObj) reactionList.append(jsonObj)
formerTimestamp = lastTimestamp formerTimestamp = lastTimestamp
if not len(reactionList) <=1: if not len(reactionList) <= 0:
lastTime = reactionList[len(reactionList) - 1]["createdAt"] lastTime = reactionList[len(reactionList) - 1]["createdAt"]
lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z')) * 1000) lastTimestamp = int(datetime.timestamp(datetime.strptime(lastTime, '%Y-%m-%dT%H:%M:%S.%f%z')) * 1000)
else: else:
@ -205,7 +261,6 @@ if getReactions:
reactList.append(emojiDict) reactList.append(emojiDict)
index = doubleList.index(react) index = doubleList.index(react)
reactList[index]["count"] += 1 reactList[index]["count"] += 1
doubleList = [] doubleList = []
@ -215,10 +270,13 @@ if getReactions:
for react in reactList: # Summarize the number of Reactions used for react in reactList: # Summarize the number of Reactions used
reactionCount += react["count"] reactionCount += react["count"]
reactText = "\n\n\nAnd used " + str(reactionCount) + " reactions:\n\n" + chr(9553) + " " initial_react_text = "\n\n\nAnd used " + str(reactionCount) + " reactions:\n\n" + chr(9553) + " "
reactText = initial_react_text
for reactionElement in reactList: for reactionElement in reactList:
reactText += str(reactionElement["count"]) + "x " + reactionElement["reaction"] + " " + chr(9553) + " " count = reactionElement["count"]
reaction = reactionElement["reaction"]
reactText += f"{count}x {reaction} " + chr(9553) + " "
else: else:
reactText = "\n\nAnd didn't use any reactions." reactText = "\n\nAnd didn't use any reactions."
else: else:
@ -228,25 +286,50 @@ for count in emojiList:
emojisTotal += count["count"] emojisTotal += count["count"]
if emojisTotal > 0: if emojisTotal > 0:
text = nickname + " has written " + str(len(noteList)) + " Notes yesterday, " + formerDate.strftime( initial_text = nickname + " has written " + str(len(noteList)) + " Notes yesterday, " + formerDate.strftime(
'%a %d-%m-%Y') + "\nand used a total of " + str(emojisTotal) + " Emojis. #miceco" + chr(8203) + chr(8203) + chr( '%a %d-%m-%Y') + "\nand used a total of " + str(emojisTotal) + " Emojis. #miceco" + chr(8203) + chr(8203) + chr(
8203) + "\n\n" + chr( 8203) + "\n\n" + chr(9553) + " "
9553) + " " text = initial_text
for element in emojiList: emoji_text = ""
text += str(element["count"]) + "x\u00A0" + element["emoji"] + " " + chr(9553) + " "
else:
text = nickname + " has written " + str(len(noteList)) + " Notes yesterday, " + formerDate.strftime(
'%a %d-%m-%Y') + "\nand didn't used any emojis. #miceco" + chr(8203) + chr(8203) + chr(
8203)
text += reactText for element in emojiList:
count = element["count"]
emoji = element["emoji"]
emoji_text += f"{count}x {emoji} " + chr(9553) + " "
else:
emoji_text = nickname + " has written " + str(len(noteList)) + " Notes yesterday, " + formerDate.strftime(
'%a %d-%m-%Y') + "\nand didn't used any emojis. #miceco" + chr(8203) + chr(8203) + chr(8203)
text += emoji_text + reactText
text = emojilib.emojize(text)
# print(text)
if max_note_length < len(text):
emoji_text = initial_text
for item in range(0,5):
count = emojiList[item]["count"]
emoji = emojiList[item]["emoji"]
emoji_text += f"{count}x {emoji} " + chr(9553) + " "
emoji_text += " and more..."
if getReactions:
reactText = initial_react_text
for item in range(0,5):
count = reactList[item]["count"]
reaction = reactList[item]["reaction"]
reactText += f"{count}x {reaction} " + chr(9553) + " "
reactText += " and more..."
text = emoji_text + reactText
text = emojilib.emojize(text)
# print(text) # print(text)
try: try:
req = requests.post(url + "/notes/create", json={ req = requests.post(url + "/notes/create", json={
"i": token, "i": token,
"visibility": "public", "visibility": noteVisibility,
"text": text "text": text
}) })
req.raise_for_status() req.raise_for_status()

View file

@ -1,2 +1,3 @@
emoji emoji==1.6.3
python-dateutil configparser~=5.2.0
requests~=2.27.1