Compare commits

...

54 Commits
v0.3 ... master

Author SHA1 Message Date
bursa-pastoris ab69ca0aa9 Merge tag 'v0.4.0' into dev 2023-12-23 12:29:44 +01:00
bursa-pastoris 7720fb1ab7 Release v0.4.0 2023-12-23 12:26:44 +01:00
bursa-pastoris 38bc5d6afe Fix Italian translation 2023-07-10 21:15:42 +02:00
bursa-pastoris 84cf9f423e Fix VERSION const for Telegram markup 2023-07-10 21:15:32 +02:00
bursa-pastoris 26e76cde2f /init -> /reset 2023-07-06 21:58:32 +02:00
bursa-pastoris b3f4e24743 Merge branch 'v0.4.0-alpha' 2023-07-06 21:58:03 +02:00
bursa-pastoris 042fd00108 Semver compliance 2023-07-06 21:57:02 +02:00
bursa-pastoris 14ba0cbdad Clean doc/RELEASE_PROCESS.md 2023-07-06 21:39:33 +02:00
bursa-pastoris 97665ba7c6 Misc fix 2023-07-06 21:38:10 +02:00
bursa-pastoris 43b1ffd8b0 Language defaults to English 2023-07-06 20:50:27 +02:00
bursa-pastoris 979aa86e9f Update doc/CHANGELOG.md 2023-06-11 17:59:36 +02:00
bursa-pastoris e9538c5c89 Update README.md 2023-06-11 17:58:25 +02:00
bursa-pastoris 86d8a484c6 Update some docs and do some free steps 2023-06-11 17:03:33 +02:00
bursa-pastoris a14da6e20f Update version 2023-06-11 16:57:37 +02:00
bursa-pastoris 3711d583b4 Update translations 2023-06-11 16:56:48 +02:00
bursa-pastoris 504876307f Update doc/template.pot 2023-06-11 16:53:11 +02:00
bursa-pastoris 8c6bdb9832 One step further - effortlessly! 2023-06-11 16:39:12 +02:00
bursa-pastoris bdc29d18db Docstrings and comments cleanup and update 2023-06-11 16:36:13 +02:00
bursa-pastoris 73daab0c18 Even more cleanup! 2023-06-11 16:35:43 +02:00
bursa-pastoris 13d921660a More cleanup 2023-06-11 16:35:37 +02:00
bursa-pastoris b8c44ebe7c Simplify stuff in /help 2023-06-11 16:08:39 +02:00
bursa-pastoris 3cf8ca1fb8 Cleanup 2023-06-11 15:44:47 +02:00
bursa-pastoris 2bef1beef1 Update dependencies 2023-06-11 15:29:03 +02:00
bursa-pastoris 21e0da854c Merge branch 'minor-fixes' into dev 2023-06-11 15:13:11 +02:00
bursa-pastoris a857520beb yell -> epiphony 2023-06-10 23:00:29 +02:00
bursa-pastoris 7b015f980b Separate /christmas and /easter cooldown 2023-06-10 22:58:16 +02:00
bursa-pastoris 4a755b2835 Merge branch 'iss9' into dev
Closes #9
2023-06-08 09:09:45 +02:00
bursa-pastoris 3920645f29 Merge branch 'iss10' into dev
Closes #10
2023-06-08 09:08:43 +02:00
bursa-pastoris 0cdec513db Remove try-except 2023-06-08 09:02:25 +02:00
bursa-pastoris daf9f5473c Remove useless import 2023-06-08 08:52:00 +02:00
bursa-pastoris 19b4939125 Update no images available message 2023-06-08 08:50:35 +02:00
bursa-pastoris 6793414f57 dict[key] -> dict.get(key, default) 2023-06-08 08:08:13 +02:00
bursa-pastoris 23a785b764 Support /christmas caption from csv 2023-06-07 21:04:58 +02:00
bursa-pastoris 2d5af5087e Merge branch 'legal-enhancements' into dev 2023-06-05 22:32:26 +02:00
bursa-pastoris 0d83497655 Caption 2023-06-05 22:27:51 +02:00
bursa-pastoris b63ca9c67a Update release process 2023-06-05 22:26:26 +02:00
bursa-pastoris 47e205f26d Send legal information in PDF 2023-06-05 22:25:14 +02:00
bursa-pastoris ec13527346 os.mkdir() -> os.makedirs() 2023-06-05 21:55:04 +02:00
bursa-pastoris feeacbfbe7 Move legal request logging 2023-05-31 17:51:26 +02:00
bursa-pastoris 124c0621f6 Fix list of commands generating anonymous logs 2023-05-30 07:59:26 +02:00
bursa-pastoris d79fcf0df4 Merge branch 'iss7' into dev
Closes #7
2023-05-30 07:33:53 +02:00
bursa-pastoris 1390468567 Add comments in /epiphony 2023-05-30 07:33:30 +02:00
bursa-pastoris 3133473fb5 Caption 2023-05-30 07:33:30 +02:00
bursa-pastoris 85577dd8b9 Delete message with /epiphony command 2023-05-30 07:33:25 +02:00
bursa-pastoris bbc7c08ac0 /epiphony voice message as reply 2023-05-30 07:33:21 +02:00
bursa-pastoris 0d082b3b77 Fix comment 2023-05-30 04:16:05 +02:00
bursa-pastoris 14964b4e80 Fix /help text
<text> in /epiphony was noted as optional but is mandatory
2023-03-24 18:42:07 +01:00
bursa-pastoris 2f82376db0 Fix typo in Italian translation 2023-03-24 18:40:33 +01:00
bursa-pastoris 83388cbe68 Note dependency on external TTS synthesizer 2023-03-24 18:28:23 +01:00
bursa-pastoris 7fe01c346f Merge branch 'release-v0.3.1' 2023-03-24 15:58:32 +01:00
bursa-pastoris e99e74816e Update doc/CHANGELOG.md 2023-03-24 15:56:30 +01:00
bursa-pastoris 7db0c761c0 Update version to v0.3.1 2023-03-24 15:51:04 +01:00
bursa-pastoris bfc9e793ce Complete inline suggestions
Add all commands that are available to all users and do not require arguments
2023-03-24 15:48:44 +01:00
bursa-pastoris a651b66898 Update copyright headers 2023-03-24 13:07:21 +01:00
18 changed files with 660 additions and 512 deletions

View File

@ -5,13 +5,20 @@ include_toc: true
Albatrobot is a personal project born as a simple bot to roll dice, but has
since then evolved with the addition of more functions, most of which is
useless. It thus evolved to the current bloat hodgepodge - but I like it the
useless. It thus became to the current bloat hodgepodge - but I like it the
same.
## Setup
To install Albatrobot, follow those steps.
Abatrobot is supposed to run in [Debian](https://www.debian.org/), a free
operating system. It should work on any other operating system, but it's not
tested on any.
Albatrobot is written in [Python 3](https://www.python.org/), therefore Python
is required to use it. Python 3 is part of any standard Debian distribution,
but you may have to install it manually in other operating systems (especially
in non-GNU/Linux based ones).
### Installation
@ -22,6 +29,10 @@ To install Albatrobot, follow those steps.
source .venv/bin/activate
python3 -m pip install -r requirements.txt
```
3. For `/epiphony` Albatrobot relies on `pyttsx3` library, that requires an
external text-to-speech synthesizer. In Debian, this dependence is
satisfied by `libespeak1`, that can be installed with `sudo apt install
libespeak1`.
### Configuration
@ -34,22 +45,24 @@ can be tuned to user's needs.
server.[^token]
- `Users`
- `Users`: a comma-separated list of the user IDs of the users allowed to use
the bot
the bot.
- `Admins`: a comma-separated user IDs of the users with admin powers. Admins
are always considered Users as well.
- `Settings`
- `Language`: the language of the bot interface
- `MsgCooldown`: the minimum time, in seconds, between two following uses of
commands `/Easter` and `/Christmas` by the same user. The time is the same
but is considered separately for each command.
- `Language`: the language of the bot interface. It must be specified with
its 2 letters code. The available languages are the ones listed in
[`locales`](./locales).
- `ChristmasCooldown`: the minimum time, in seconds, between two consecutive
uses of command `/Christmas` by the same user.
- `EasterCooldown`: same as above, for `/Easter`.
- `Proxy`: proxy settings to connect to Telegram's bot API. The string must
follow the syntax
`<protocol>://[<username[:<password>]@]<hostname>[:<port>]` (e.g.
`socks5://127.0.0.1:9050`)
- `YellLang`: language for `/yell` voice messages
- `YellSpeed`: speed for `/yell` voice messages
`socks5://127.0.0.1:9050`).
- `EpiphonyLang`: language for `/Epiphony` voice messages.
- `EpiphonySpeed`: speed for `/Epiphony` voice messages.
- `Resources`
- `CitePath`: path of the document containing the citations for `/Easter`
- `CiteArchive`: path of the document containing the citations for `/Easter`
command.
- `ImgPath`: path of the document containing the images for `Christmas`
command.
@ -68,10 +81,9 @@ opened, then save and close.
If you run Albatrobot this way - the recommended one - consider the following:
1. `sleep 10` adds a delay of 10 seconds. It is necessary to allow the system
to set the network up and prevents errors due to impossibility to connect to
the Internet and to Telegram APIs. You can change the time to comply with
your necessities.
1. `sleep 10` adds a delay of 10 seconds. It may be necessary to allow the
system to set the network up and prevents errors due to impossibility to
connect to the Internet and to Telegram APIs.
2. If Albatrobot can't be launched, some error information should be saved in
`/tmp/albatrobot.txt`.
@ -154,7 +166,7 @@ Check:
2. that only one instance of the albatrobot is active for the same Telegram bot
user
**Albatrobot says that there are no avilable citations or images**
### Albatrobot says that there are no avilable citations or images
Check:

View File

@ -1,26 +1,23 @@
"""
Albatrobot - Telegram bot for RPG groups and similar
Copyright (C) 2019, 2020, 2021, 2022 bursa-pastoris
This file is part of Albatrobot.
Albatrobot is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
Albatrobot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Albatrobot. If not, see <https://www.gnu.org/licenses/>.
"""
# Albatrobot - Telegram bot for RPG groups and similar
# Copyright (C) 2019, 2020, 2021, 2022, 2023 bursa-pastoris
#
# This file is part of Albatrobot.
#
# Albatrobot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Albatrobot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Albatrobot. If not, see <https://www.gnu.org/licenses/>.
import csv
from datetime import datetime
import glob
import hashlib
import logging
import os
@ -34,15 +31,14 @@ import Levenshtein
import psutil
from rolldice import roll_dice, rolldice
from telegram import BotCommand
from telegram.constants import ChatAction, ChatType, ParseMode
from telegram.constants import ChatAction, ChatMemberStatus, ChatType, ParseMode
from constants import *
# Prepare paths
required_paths = ['log',TMPVOICEDIR]
required_paths = [LOGDIR,TMPVOICEDIR]
for i in required_paths:
if not os.path.exists(i):
os.mkdir(i)
os.makedirs(i,exist_ok=True)
# Logging
logger = logging.getLogger('albatrobot_logger')
@ -51,7 +47,7 @@ logformat = logging.Formatter('%(asctime)s %(levelname)s: %(message)s')
loghandler_toconsole = logging.StreamHandler()
loghandler_toconsole.setLevel(logging.DEBUG)
loghandler_toconsole.setFormatter(logformat)
loghandler_tofile = logging.FileHandler('log/albatrobot.log')
loghandler_tofile = logging.FileHandler(f'{LOGDIR}/albatrobot.log')
loghandler_tofile.setLevel(logging.DEBUG)
loghandler_tofile.setFormatter(logformat)
logger.addHandler(loghandler_toconsole)
@ -62,7 +58,7 @@ logger.addHandler(loghandler_tofile)
def closest(good_list, item):
"""Return the item(s) of good_list closest to item.
"Closest" means "with the shortest Levenshtein distance.
"Closest" means "with the shortest Levenshtein distance".
"""
distances = {}
for i in good_list:
@ -97,7 +93,7 @@ async def unknown_command(update, context):
# Basic functions
async def start(update, context):
"""Show a message when a user contacts the bot for the first time."""
"""Show basic info when a user contacts the bot for the first time."""
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_("Hello, I'm Albatrobot\! Type \/help for help\!\n"
@ -128,17 +124,17 @@ async def help(update, context):
"""Show a help message.
The message doesn't correspond to the inline suggestion set in
@BotFather, that must be set manually through a Telegram client.
@BotFather. They can be set issuing the command /init.
"""
# Common commands
ccom_header = _('*Albatrobot commands*')
ccom_help = {
com_header = _('*Albatrobot commands*')
com_help = {
_('christmas'):_('get an image'),
_('easter')+_(' `\(\<author\>\)`'):_('get a citation from given author,'
' or a random one if no author is specified\.'),
_('end\_of\_year\_dinner'):_('send all citations in the archive to a'
' random user\.'),
_('epiphony')+_(' `\(\<text\>\)`'):_('get a voice message from'
_('epiphony')+_(' `<text\>`'):_('get a voice message from'
' Albatrobot reading given text'),
_('help'):_('get help about bot commands\.'),
_('legal'):_('get legal info about privacy and copyright\.'),
@ -147,53 +143,52 @@ async def help(update, context):
' modifiers\.'),
_('version'):_("get Albatrobot's version")
}
ccom_help = [f'\- \/{i}: {ccom_help[i]}'
for i in ccom_help]
ccom_help.sort()
ccom_help = '\n'.join(ccom_help)
ccom_help = f'{ccom_header}\n{ccom_help}'
com_help = [f'\- \/{i}: {com_help[i]}' for i in com_help]
com_help.sort()
com_help = '\n'.join(com_help)
com_help = f'{com_header}\n{com_help}'
# Admin commands
acom_header = _('*Additional commands for bot admins*')
acom_help = {
_('init'):_('reinitialize the bot\. This updates inline suggestions'
adm_header = _('*Additional commands for bot admins*')
adm_help = {
_('reset'):_('reset the bot\. This updates inline suggestions'
' and purges /epiphony cached files\.'),
_('stop'):_('stop Albatrobot\. To be used _only_ in case of emergency:'
' restarting the bot after this command is used requires direct'
' access to the server\.')
}
acom_help = [f'\- \/{i}: {acom_help[i]}'
for i in acom_help]
acom_help.sort()
acom_help = '\n'.join(acom_help)
acom_help = f'{acom_header}\n{acom_help}'
adm_help = [f'\- \/{i}: {adm_help[i]}' for i in adm_help]
adm_help.sort()
adm_help = '\n'.join(adm_help)
adm_help = f'{adm_header}\n{adm_help}'
# Addendum
non_admin_addendum = _(
nonadm_addendum = _(
'Bot admins have access to additional commands and can get help on'
' them using /help in a private chat\.'
)
# Actually sending stuff
# Actually send stuff
if (update.effective_chat.type == ChatType.PRIVATE
and update.effective_user.id in ADMINS):
await context.bot.send_message(
chat_id=update.effective_user.id,
text=_(f'{ccom_help}\n\n{acom_help}'),
parse_mode=ParseMode.MARKDOWN_V2
)
help_text = _(f'{com_help}\n\n{adm_help}')
else:
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_(f'{ccom_help}\n\n{non_admin_addendum}'),
parse_mode=ParseMode.MARKDOWN_V2
)
help_text = _(f'{com_help}\n\n{nonadm_addendum}')
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=help_text,
parse_mode=ParseMode.MARKDOWN_V2
)
async def init(update, context):
"""Initialize the bot."""
async def reset(update, context):
"""Reset the bot."""
# Set commands suggestions
commands=[BotCommand(_('roll'),_('Roll dice'))]
commands=[BotCommand(_('christmas'),_('Get an image')),
BotCommand(_('easter'),_('Get a citation')),
BotCommand(_('end_of_year_dinner'),_('Send all citations to a random user')),
BotCommand(_('help'),_('Get help'))]
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_('Initializing...'))
@ -208,17 +203,25 @@ async def init(update, context):
async def legal(update, context):
"""
Send legal information (privacy and copyright).
Send legal information about privacy and copyright.
"""
logger.info('A user asked for legal info.')
if LANG != "en":
note=_('The only official version is the English one and any'
' imperfect translation would be misleading. Therefore, this'
' document will not be translated.')
else:
note=""
await context.bot.send_chat_action(
chat_id=update.effective_chat.id,
action=ChatAction.UPLOAD_DOCUMENT)
with open('doc/LEGAL.md','rb') as legalnotes:
with open('doc/LEGAL.pdf','rb') as legalnotes:
await context.bot.send_document(
chat_id=update.effective_chat.id,
document=legalnotes,
filename='albatrobot-legal-notes.txt')
logger.info('A user asked for legal info.')
filename='albatrobot-legal-notes.pdf',
caption=note
)
async def version(update, context):
@ -232,22 +235,23 @@ async def version(update, context):
# Commands
async def christmas(update, context):
"""Send a (hopefully funny) image from the archive."""
imgs = glob.glob(str(IMGPATH+'/*'))
try:
last_msg = context.user_data['last_christmas']
if datetime.now()-last_msg < MSGCOOLDOWN:
await context.bot.send_message(
chat_id=update.effective_user.id,
text=_("Christmas is good, but you can't invoke it so often! "
"Try again in some seconds...")
)
logger.info('A user wants too much Christmas.')
return
# If last_christmas doesn't exist, it just means the user never used
# /christmas since last bot start.
except KeyError:
pass
"""Send a random image from the archive."""
last_msg = context.user_data.get('last_christmas',
datetime.fromisoformat('1970-01-01T00:00'))
if datetime.now()-last_msg < CHRISTMASCOOLDOWN:
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_("Christmas is good, but you can't invoke it so often! "
"Try again in some seconds...")
)
logger.info('A user wants too much Christmas.')
return
with open(f'{IMGPATH}/imgs.csv','r') as imgs_file:
imgs = list(csv.DictReader(imgs_file))
img = random.choice(imgs)
img_file = img['filename']
img_capt = img['caption']
await context.bot.send_chat_action(
chat_id=update.effective_chat.id,
@ -255,7 +259,8 @@ async def christmas(update, context):
)
await context.bot.send_photo(
chat_id=update.effective_chat.id,
photo=open(random.choice(imgs), 'rb')
photo=open(f'{IMGPATH}/{img_file}', 'rb'),
caption=img_capt
)
context.user_data['last_christmas'] = datetime.now()
@ -263,22 +268,18 @@ async def christmas(update, context):
async def easter(update, context):
"""Send a citation from the archive.
User can either choose the source or let the bot pick a random one.
User can either choose the author or let the bot pick a random one.
"""
try:
last_msg = context.user_data['last_easter']
if datetime.now()-last_msg < MSGCOOLDOWN:
await context.bot.send_message(
chat_id=update.effective_user.id,
text=_("Easter is good, but you can't invoke it so often!"
" Retry in some seconds...")
)
logger.info('A user wants too much Easter.')
return
# If last_easter doesn't exist, it just means the user never used /easter
# since last bot start.
except KeyError:
pass
last_msg = context.user_data.get('last_easter',
datetime.fromisoformat('1970-01-01T00:00'))
if datetime.now()-last_msg < EASTERCOOLDOWN:
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_("Easter is good, but you can't invoke it so often!"
" Retry in some seconds...")
)
logger.info('A user wants too much Easter.')
return
with open(CITARCHIVE,'r') as cits_file:
cits = csv.DictReader(cits_file)
@ -331,8 +332,6 @@ async def easter(update, context):
async def end_of_year_dinner(update, context):
"""Send a user each citation from the archive."""
# Importing here is so that the citations list can be updated without
# restarting the bot.
with open(CITARCHIVE,'r') as cits_file:
cits_archive = list(csv.DictReader(cits_file))
cits_number = 0
@ -366,12 +365,15 @@ async def end_of_year_dinner(update, context):
async def epiphony(update, context):
sentence = ' '.join(context.args).upper()
# Handle command without args
if len(sentence) == 0:
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=_('What should I say?')
)
# Handle command with args
else:
# Generate and send audio
sentence_hash = hashlib.md5(sentence.encode(encoding='UTF-8')).hexdigest()
voice_file = f'{TMPVOICEDIR}/{sentence_hash}.ogg'
await context.bot.send_chat_action(
@ -379,15 +381,31 @@ async def epiphony(update, context):
action=ChatAction.RECORD_VOICE)
if not os.path.exists(voice_file):
engine = pyttsx3.init()
engine.setProperty('voice',YELLLANG)
engine.setProperty('rate',YELLSPEED)
engine.setProperty('voice',EPIPHONYLANG)
engine.setProperty('rate',EPIPHONYSPEED)
engine.save_to_file(sentence,voice_file)
engine.runAndWait()
time.sleep(1) # Workaround to prevent ReferenceError due to using
# pyttsx3 with threads
# pyttsx3 with asyncio
await context.bot.send_voice(
chat_id=update.effective_chat.id,
voice=open(voice_file,'rb'))
voice=open(voice_file,'rb'),
reply_to_message_id=update.effective_message.reply_to_message.message_id
if update.effective_message.reply_to_message else None,
caption=_('Voice message from {sender_name}.'.format(
sender_name=update.effective_user.first_name))
)
# If in group chat and have permission, delete the message that issued
# the command
bot_data = await context.bot.get_me()
bot_chatmember = await context.bot.get_chat_member(
chat_id=update.effective_chat.id,
user_id=bot_data.id)
if (bot_chatmember.status == ChatMemberStatus.ADMINISTRATOR
and bot_chatmember.can_delete_messages):
await context.bot.delete_message(
chat_id=update.effective_chat.id,
message_id=update.effective_message.message_id)
async def roll(update, context):

View File

@ -12,11 +12,12 @@ ADMINS = [int(admin) for admin in config["Users"]["Admins"].split(",")]
USERS = [int(user) for user in config["Users"]["Users"].split(",")]
# Settings
LANG = config["Settings"]["Language"]
MSGCOOLDOWN = timedelta(seconds=int(config["Settings"]["MsgCooldown"]))
LANG = config["Settings"]["Language"] if len(config["Settings"]["Language"]) > 0 else "en"
CHRISTMASCOOLDOWN = timedelta(seconds=int(config["Settings"]["ChristmasCooldown"]))
EASTERCOOLDOWN = timedelta(seconds=int(config["Settings"]["EasterCooldown"]))
PROXY = config["Settings"]["Proxy"]
YELLLANG = config['Settings']['YellLang']
YELLSPEED = config['Settings']['YellSpeed']
EPIPHONYLANG = config['Settings']['EpiphonyLang']
EPIPHONYSPEED = config['Settings']['EpiphonySpeed']
# Resources
CITARCHIVE = config["Resources"]["CitArchive"]
@ -24,4 +25,5 @@ IMGPATH = config["Resources"]["ImgPath"]
# Private
TMPVOICEDIR = 'tmp'
VERSION = "0.3"
LOGDIR = 'log'
VERSION = '0.4.0'

View File

@ -3,6 +3,44 @@ gitea: none
include_toc: true
---
## v0.4.0
### Misc
- Fix `VERSION` in `constants.py` to allow Telegram markup
- Fix Italian translation
## v0.4.0-alpha
### Features
- In groups, `/Epiphony` now:
- deletes the message issuing the command,
- sends the voice message as an answer to the same message to wich the
command was issued as a reply to (if any)
- Add support for captions to `/Christmas` images
- `/Christmas` and `/Easter` cooldown times are now independent from each other
### Misc
- If no language is set, default to English
- `/legal` now sends the information in PDF (instead of TXT)
- If the instance is in a language other than English, `/legal` now explains
that and why the legal info will not be translated
- Fix privacy info (without privacy implications: simply, `/legal` was added to
the list of commands that generate anonymous logs)
- Fix Italian translation
- Fix and improve documentation
- Code cleanup
- Minor fixes and enhancements
## V0.3.1
### Misc
- Update copyright headers
- Add inline suggestions for all common commands that don't require arguments
- Add stuff to v0.3 changelog
## v0.3
### New features
@ -16,8 +54,13 @@ include_toc: true
### Enhancements
- Better help texts
- Citations for /easter are now stored in a CSV file
- Enhance "no images available" image
### Bug fixes
- Close #4, #5 and #6
### Code
- Constants moved to own module

View File

@ -10,7 +10,7 @@ Everyone is welcome to propose his contribution:
But note that, as Albatrobot is a personal project, I will merge only the
contributions that I find useful or interesting *for me*. However, everyone
can enjoy the rights granted by [AGPL-3.0-only license](./LICENSE) to fork the
project and do whatever they want on their copies (as long as the license is
project and do whatever he want on their copies (as long as the license is
honoured).

View File

@ -20,10 +20,11 @@ Note however that:
Also, anonymous logs are stored:
* when a user uses one of the following commands:
* `/source`
* `/end_of_year_dinner`
* `/christmas`, if the user hits the time limit
* `/easter`, if the user hits the time limit or asks for an unknown author
* `/end_of_year_dinner`
* `/legal`
* `/source`
* whenever an error is raised
The logs are intended for debug and issue resolution only and *never* contain

BIN
doc/LEGAL.pdf Normal file

Binary file not shown.

View File

@ -16,6 +16,7 @@ To release a new version:
- [ ] in `constants.py`
- [ ] in the updated translations
- [ ] Update documentation not listed below
- [ ] Update `doc/LEGAL.pdf`
- [ ] Update `doc/README.md`
- [ ] Update `doc/CHANGELOG.md`
- [ ] _At least now_, test _each command_, both as admin and simple user, to

View File

@ -3,12 +3,11 @@
# This file is distributed under the same license as the Albatrobot package.
# bursa-pastoris <bursapastoris at disroot dot org>, 2021, 2023.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Albatrobot 0.3\n"
"Project-Id-Version: Albatrobot 0.4.0-alpha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-23 00:00+0000\n"
"POT-Creation-Date: 2023-06-11 00:00+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,55 +16,55 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: main.py:48 main.py:60 albatrobot.py:161
#: main.py:46 main.py:58 albatrobot.py:156
msgid "stop"
msgstr ""
#: main.py:48 main.py:69 albatrobot.py:159
#: main.py:46 main.py:67 albatrobot.py:154
msgid "init"
msgstr ""
#: main.py:65 albatrobot.py:143
#: main.py:63 albatrobot.py:139 albatrobot.py:191
msgid "help"
msgstr ""
#: main.py:73 albatrobot.py:144
#: main.py:71 albatrobot.py:140
msgid "legal"
msgstr ""
#: main.py:77 albatrobot.py:148
#: main.py:75 albatrobot.py:144
msgid "version"
msgstr ""
#: main.py:84 albatrobot.py:136
#: main.py:82 albatrobot.py:132 albatrobot.py:188
msgid "christmas"
msgstr ""
#: main.py:88 albatrobot.py:137
#: main.py:86 albatrobot.py:133 albatrobot.py:189
msgid "easter"
msgstr ""
#: main.py:92
#: main.py:90 albatrobot.py:190
msgid "end_of_year_dinner"
msgstr ""
#: main.py:96 albatrobot.py:141
#: main.py:94 albatrobot.py:137
msgid "epiphony"
msgstr ""
#: main.py:100 albatrobot.py:145 albatrobot.py:196
#: main.py:98 albatrobot.py:141
msgid "roll"
msgstr ""
#: albatrobot.py:81
#: albatrobot.py:77
msgid "User not authorized."
msgstr ""
#: albatrobot.py:89
#: albatrobot.py:85
msgid "Unknown command."
msgstr ""
#: albatrobot.py:103
#: albatrobot.py:99
msgid ""
"Hello, I'm Albatrobot\\! Type \\/help for help\\!\n"
"\n"
@ -76,140 +75,158 @@ msgid ""
"albatrobot)\\._"
msgstr ""
#: albatrobot.py:121
#: albatrobot.py:117
msgid "Albatrobot will be stopped in a few moments."
msgstr ""
#: albatrobot.py:134
#: albatrobot.py:130
msgid "*Albatrobot commands*"
msgstr ""
#: albatrobot.py:136
#: albatrobot.py:132
msgid "get an image"
msgstr ""
#: albatrobot.py:137
#: albatrobot.py:133
msgid " `\\(\\<author\\>\\)`"
msgstr ""
#: albatrobot.py:137
#: albatrobot.py:133
msgid ""
"get a citation from given author, or a random one if no author is "
"specified\\."
msgstr ""
#: albatrobot.py:139
#: albatrobot.py:135
msgid "end\\_of\\_year\\_dinner"
msgstr ""
#: albatrobot.py:139
#: albatrobot.py:135
msgid "send all citations in the archive to a random user\\."
msgstr ""
#: albatrobot.py:141
msgid " `\\(\\<text\\>\\)`"
#: albatrobot.py:137
msgid " `<text\\>`"
msgstr ""
#: albatrobot.py:141
#: albatrobot.py:137
msgid "get a voice message from Albatrobot reading given text"
msgstr ""
#: albatrobot.py:143
#: albatrobot.py:139
msgid "get help about bot commands\\."
msgstr ""
#: albatrobot.py:144
#: albatrobot.py:140
msgid "get legal info about privacy and copyright\\."
msgstr ""
#: albatrobot.py:145
#: albatrobot.py:141
msgid " `\\<dice\\>\\(\\<modifiers\\>\\)`"
msgstr ""
#: albatrobot.py:145
#: albatrobot.py:141
msgid ""
"roll dice, with or without modifiers\\. Launch without arguments to get help "
"on the modifiers\\."
msgstr ""
#: albatrobot.py:148
#: albatrobot.py:144
msgid "get Albatrobot's version"
msgstr ""
#: albatrobot.py:157
#: albatrobot.py:152
msgid "*Additional commands for bot admins*"
msgstr ""
#: albatrobot.py:159
#: albatrobot.py:154
msgid ""
"reinitialize the bot\\. This updates inline suggestions and purges /epiphony "
"cached files\\."
msgstr ""
#: albatrobot.py:161
#: albatrobot.py:156
msgid ""
"stop Albatrobot\\. To be used _only_ in case of emergency: restarting the "
"bot after this command is used requires direct access to the server\\."
msgstr ""
#: albatrobot.py:173
#: albatrobot.py:167
msgid ""
"Bot admins have access to additional commands and can get help on them "
"using /help in a private chat\\."
msgstr ""
#: albatrobot.py:182
#: albatrobot.py:174
#, python-brace-format
msgid ""
"{ccom_help}\n"
"{com_help}\n"
"\n"
"{acom_help}"
"{adm_help}"
msgstr ""
#: albatrobot.py:176
#, python-brace-format
msgid ""
"{com_help}\n"
"\n"
"{nonadm_addendum}"
msgstr ""
#: albatrobot.py:188
#, python-brace-format
msgid ""
"{ccom_help}\n"
"\n"
"{non_admin_addendum}"
msgid "Get an image"
msgstr ""
#: albatrobot.py:196
msgid "Roll dice"
#: albatrobot.py:189
msgid "Get a citation"
msgstr ""
#: albatrobot.py:199
#: albatrobot.py:190
msgid "Send all citations to a random user"
msgstr ""
#: albatrobot.py:191
msgid "Get help"
msgstr ""
#: albatrobot.py:194
msgid "Initializing..."
msgstr ""
#: albatrobot.py:203
#: albatrobot.py:198
msgid "Done"
msgstr ""
#: albatrobot.py:228
#: albatrobot.py:217
msgid ""
"The only official version is the English one and any imperfect translation "
"would be misleading. Therefore, this document will not be translated."
msgstr ""
#: albatrobot.py:227
msgid "*Albatrobot's version:* {}"
msgstr ""
#: albatrobot.py:242
#: albatrobot.py:240
msgid ""
"Christmas is good, but you can't invoke it so often! Try again in some "
"seconds..."
msgstr ""
#: albatrobot.py:273
#: albatrobot.py:274
msgid ""
"Easter is good, but you can't invoke it so often! Retry in some seconds..."
msgstr ""
#: albatrobot.py:296
#: albatrobot.py:293
msgid "The most similar is {}."
msgstr ""
#: albatrobot.py:300
#: albatrobot.py:297
msgid "The most similar are {} and {}."
msgstr ""
#: albatrobot.py:304
#: albatrobot.py:301
#, python-brace-format
msgid ""
"Author {required_author} is not present in the archive! {suggestion}\n"
@ -217,7 +234,7 @@ msgid ""
"N.b.: CaSe Is ImPoRtAnT!"
msgstr ""
#: albatrobot.py:324 albatrobot.py:352
#: albatrobot.py:321 albatrobot.py:347
#, python-brace-format
msgid ""
"{cit}\n"
@ -225,142 +242,147 @@ msgid ""
"~{author}"
msgstr ""
#: albatrobot.py:345
#: albatrobot.py:340
msgid "Hello there, here an end of year dinner offered by {}!"
msgstr ""
#: albatrobot.py:359
#: albatrobot.py:354
#, python-brace-format
msgid "End of year dinner of {cits_number} plates delvered to {dest}!"
msgstr ""
#: albatrobot.py:372
#: albatrobot.py:368
msgid "What should I say?"
msgstr ""
#: albatrobot.py:402
msgid "add `n` to the roll"
msgstr ""
#: albatrobot.py:403
msgid "subtract `n` from the roll"
msgstr ""
#: albatrobot.py:404
msgid "multiply the roll by `n`"
msgstr ""
#: albatrobot.py:405
msgid "divide the roll by `n`"
msgstr ""
#: albatrobot.py:406
msgid "floor divide the roll by `n`"
msgstr ""
#: albatrobot.py:407
msgid "exponentiate the roll to `n`"
msgstr ""
#: albatrobot.py:408
msgid "keep highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:409
msgid "keep lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:410
msgid "drop highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:411
msgid "drop lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:412
msgid "explode rolls equal to `n` \\(defaults to die size\\)"
msgstr ""
#: albatrobot.py:413
msgid "explode rolls lower than `n`"
msgstr ""
#: albatrobot.py:414
msgid "explode rolls higher than `n`"
msgstr ""
#: albatrobot.py:415
msgid "count failures as rolls lower than `n`"
#: albatrobot.py:391
#, python-brace-format
msgid "Voice message from {sender_name}."
msgstr ""
#: albatrobot.py:416
msgid "count failures as rolls higher than `n`"
msgid "add `n` to the roll"
msgstr ""
#: albatrobot.py:417
msgid "count successes as rolls lower than `n`"
msgid "subtract `n` from the roll"
msgstr ""
#: albatrobot.py:418
msgid "count successes as rolls higher than `n`"
msgid "multiply the roll by `n`"
msgstr ""
#: albatrobot.py:419
msgid "penetrate rolls equal to dice size"
msgid "divide the roll by `n`"
msgstr ""
#: albatrobot.py:420
msgid "penetrate rolls lower than `n`"
msgid "floor divide the roll by `n`"
msgstr ""
#: albatrobot.py:421
msgid "penetrate rolls higher than `n`"
msgid "exponentiate the roll to `n`"
msgstr ""
#: albatrobot.py:422
msgid "add `n` to each roll"
msgid "keep highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:423
msgid "subtract `n` from each roll"
msgid "keep lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:424
msgid "multiply by `n` each roll"
msgid "drop highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:425
msgid "drop lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:426
msgid "explode rolls equal to `n` \\(defaults to die size\\)"
msgstr ""
#: albatrobot.py:427
msgid "explode rolls lower than `n`"
msgstr ""
#: albatrobot.py:428
msgid "explode rolls higher than `n`"
msgstr ""
#: albatrobot.py:429
msgid "count failures as rolls lower than `n`"
msgstr ""
#: albatrobot.py:430
msgid "count failures as rolls higher than `n`"
msgstr ""
#: albatrobot.py:431
msgid "count successes as rolls lower than `n`"
msgstr ""
#: albatrobot.py:432
msgid "count successes as rolls higher than `n`"
msgstr ""
#: albatrobot.py:433
msgid "penetrate rolls equal to dice size"
msgstr ""
#: albatrobot.py:434
msgid "penetrate rolls lower than `n`"
msgstr ""
#: albatrobot.py:435
msgid "penetrate rolls higher than `n`"
msgstr ""
#: albatrobot.py:436
msgid "add `n` to each roll"
msgstr ""
#: albatrobot.py:437
msgid "subtract `n` from each roll"
msgstr ""
#: albatrobot.py:438
msgid "multiply by `n` each roll"
msgstr ""
#: albatrobot.py:439
msgid ""
"reroll each dice that rolled `n` until there are no `n` left\\(defaults to "
"`1`\\)"
msgstr ""
#: albatrobot.py:427
#: albatrobot.py:441
msgid "reroll once each dice that rolled `n` \\(defaults to 1\\)"
msgstr ""
#: albatrobot.py:429
#: albatrobot.py:443
msgid ""
"reroll dice that rolled lower than `n` until there are no results lower than "
"`n` left"
msgstr ""
#: albatrobot.py:431
#: albatrobot.py:445
msgid ""
"reroll dice that rolled higher than `n` until there no results higher than "
"`n` left"
msgstr ""
#: albatrobot.py:433
#: albatrobot.py:447
msgid "reroll once dice that roll lower than `n`"
msgstr ""
#: albatrobot.py:434
#: albatrobot.py:448
msgid "reroll once dice that roll higher than `n`"
msgstr ""
#: albatrobot.py:439
#: albatrobot.py:453
msgid ""
"To roll, use the syntax `\\<number of dice\\>d\\<dice size\\>`\\. You can "
"also use the following modifiers\\. Note that:\n"
@ -372,15 +394,15 @@ msgid ""
"\n"
msgstr ""
#: albatrobot.py:458
#: albatrobot.py:472
msgid "You can roll up to 500 dice with up to 500 faces at once!"
msgstr ""
#: albatrobot.py:465
#: albatrobot.py:479
#, python-brace-format
msgid "{user_name} rolled {rolls} = {result}"
msgstr ""
#: albatrobot.py:473
#: albatrobot.py:487
msgid "You used a wrong syntax!"
msgstr ""

View File

@ -1,14 +1,14 @@
# Albatrobot translation.
# Copyright (C) 2021 bursa-pastoris
# Copyright (C) 2021, 2023 bursa-pastoris
# This file is distributed under the same license as the Albatrobot package.
# bursa-pastoris <bursapastoris at disroot dot org>, 2021, 2023.
#
msgid ""
msgstr ""
"Project-Id-Version: 0.3\n"
"Project-Id-Version: Albatrobot 0.4.0-alhpa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-23 00:00+0000\n"
"PO-Revision-Date: 2023-03-0 00:00+0000\n"
"POT-Creation-Date: 2023-06-11 00:00+0000\n"
"PO-Revision-Date: 2023-06-11 00:00+0000\n"
"Last-Translator: bursa-pastoris <bursapastoris at disroot dot org>\n"
"Language-Team: Italian <bursapastoris at disroot dot org>\n"
"Language: it\n"
@ -16,55 +16,55 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: main.py:48 main.py:60 albatrobot.py:161
#: main.py:46 main.py:58 albatrobot.py:156
msgid "stop"
msgstr "stop"
#: main.py:48 main.py:69 albatrobot.py:159
#: main.py:46 main.py:67 albatrobot.py:154
msgid "init"
msgstr "imposta"
#: main.py:65 albatrobot.py:143
#: main.py:63 albatrobot.py:139 albatrobot.py:191
msgid "help"
msgstr "aiuto"
#: main.py:73 albatrobot.py:144
#: main.py:71 albatrobot.py:140
msgid "legal"
msgstr "burocrazia"
#: main.py:77 albatrobot.py:148
#: main.py:75 albatrobot.py:144
msgid "version"
msgstr "versione"
#: main.py:84 albatrobot.py:136
#: main.py:82 albatrobot.py:132 albatrobot.py:188
msgid "christmas"
msgstr "natale"
#: main.py:88 albatrobot.py:137
#: main.py:86 albatrobot.py:133 albatrobot.py:189
msgid "easter"
msgstr "pasqua"
#: main.py:92
#: main.py:90 albatrobot.py:190
msgid "end_of_year_dinner"
msgstr "cenone_di_fine_anno"
#: main.py:96 albatrobot.py:141
#: main.py:94 albatrobot.py:137
msgid "epiphony"
msgstr "epifonia"
#: main.py:100 albatrobot.py:145 albatrobot.py:196
#: main.py:98 albatrobot.py:141
msgid "roll"
msgstr "tira"
#: albatrobot.py:81
#: albatrobot.py:77
msgid "User not authorized."
msgstr "Utente non autorizzato."
#: albatrobot.py:89
#: albatrobot.py:85
msgid "Unknown command."
msgstr "Comando sconosciuto."
#: albatrobot.py:103
#: albatrobot.py:99
msgid ""
"Hello, I'm Albatrobot\\! Type \\/help for help\\!\n"
"\n"
@ -82,23 +82,23 @@ msgstr ""
"pubblicamente disponibile su [Disroot](https:\\/\\/git.disroot.org\\/"
"bursapastoris\\/albatrobot)\\._"
#: albatrobot.py:121
#: albatrobot.py:117
msgid "Albatrobot will be stopped in a few moments."
msgstr "L'Albatrobot sarà arrestato tra un istante."
#: albatrobot.py:134
#: albatrobot.py:130
msgid "*Albatrobot commands*"
msgstr "*Comandi dell'Albatrobot*"
#: albatrobot.py:136
#: albatrobot.py:132
msgid "get an image"
msgstr "ricevi un'immagine"
#: albatrobot.py:137
#: albatrobot.py:133
msgid " `\\(\\<author\\>\\)`"
msgstr " `\\(\\<autore\\>\\)`"
#: albatrobot.py:137
#: albatrobot.py:133
msgid ""
"get a citation from given author, or a random one if no author is "
"specified\\."
@ -106,36 +106,36 @@ msgstr ""
"ricevi una citazione dall'autore indicato, o da uno casuale se non viene "
"specificato nessun autore\\."
#: albatrobot.py:139
#: albatrobot.py:135
msgid "end\\_of\\_year\\_dinner"
msgstr "cenone\\_di\\_fine\\_anno"
#: albatrobot.py:139
#: albatrobot.py:135
msgid "send all citations in the archive to a random user\\."
msgstr "invia tutte le citazioni nell'archivio a un utente casuale\\."
#: albatrobot.py:141
msgid " `\\(\\<text\\>\\)`"
msgstr " `\\(\\testo\\>\\)`"
#: albatrobot.py:137
msgid " `<text\\>`"
msgstr " `<testo\\>`"
#: albatrobot.py:141
#: albatrobot.py:137
msgid "get a voice message from Albatrobot reading given text"
msgstr ""
"ricevi un messaggio vocale dall'Albatrobot che legge il testo specificato"
#: albatrobot.py:143
#: albatrobot.py:139
msgid "get help about bot commands\\."
msgstr "ricevi aiuto sui comandi del bot\\."
#: albatrobot.py:144
#: albatrobot.py:140
msgid "get legal info about privacy and copyright\\."
msgstr "ricevi informazioni legali su riservatezza e diritto d'autore\\."
#: albatrobot.py:145
#: albatrobot.py:141
msgid " `\\<dice\\>\\(\\<modifiers\\>\\)`"
msgstr " `\\dadi\\>\\(\\<modificatori\\>\\)`"
#: albatrobot.py:145
#: albatrobot.py:141
msgid ""
"roll dice, with or without modifiers\\. Launch without arguments to get help "
"on the modifiers\\."
@ -143,15 +143,15 @@ msgstr ""
"tira dei dadi, con o senza modificatori\\. Lancia senza argomenti per "
"ricevere aiuto sui modificatori\\."
#: albatrobot.py:148
#: albatrobot.py:144
msgid "get Albatrobot's version"
msgstr "ricevi la versione dell'Albatrobot"
#: albatrobot.py:157
#: albatrobot.py:152
msgid "*Additional commands for bot admins*"
msgstr "*Comandi aggiuntivi per gli amministratori del bot*"
#: albatrobot.py:159
#: albatrobot.py:154
msgid ""
"reinitialize the bot\\. This updates inline suggestions and purges /epiphony "
"cached files\\."
@ -159,16 +159,16 @@ msgstr ""
"reimposta il bot\\. Questo aggiorna i suggerimenti in linea e rimuove i "
"documenti conservati per /epifonia\\."
#: albatrobot.py:161
#: albatrobot.py:156
msgid ""
"stop Albatrobot\\. To be used _only_ in case of emergency: restarting the "
"bot after this command is used requires direct access to the server\\."
msgstr ""
"arresta l'ALbatrobot\\. Da usare _solo_ in caso di emergenza: riavviare il "
"arresta l'Albatrobot\\. Da usare _solo_ in caso di emergenza: riavviare il "
"bot dopo che questo comando è stato utilizzato richiede accesso diretto al "
"server\\."
#: albatrobot.py:173
#: albatrobot.py:167
msgid ""
"Bot admins have access to additional commands and can get help on them "
"using /help in a private chat\\."
@ -176,45 +176,63 @@ msgstr ""
"Gli amministratori del bot hanno accesso a comandi aggiuntivi e possono "
"ricevere aiuto su di essi usando /aiuto in una conversazione privata\\."
#: albatrobot.py:182
#, python-brace-format
#: albatrobot.py:174
msgid ""
"{ccom_help}\n"
"{com_help}\n"
"\n"
"{acom_help}"
"{adm_help}"
msgstr ""
"{ccom_help}\n"
"{com_help}\n"
"\n"
"{acom_help}"
"{adm_help}"
#: albatrobot.py:176
msgid ""
"{com_help}\n"
"\n"
"{nonadm_addendum}"
msgstr ""
"{com_help}\n"
"\n"
"{nonadm_addendum}"
#: albatrobot.py:188
#, python-brace-format
msgid ""
"{ccom_help}\n"
"\n"
"{non_admin_addendum}"
msgstr ""
"{ccom_help}\n"
"\n"
"{non_admin_addendum}"
msgid "Get an image"
msgstr "Ricevi un'immagine"
#: albatrobot.py:196
msgid "Roll dice"
msgstr "Tira dei dadi"
#: albatrobot.py:189
msgid "Get a citation"
msgstr "Ricevi una citazione"
#: albatrobot.py:199
#: albatrobot.py:190
msgid "Send all citations to a random user"
msgstr "Invia tutte le citazioni a un utente casuale"
#: albatrobot.py:191
msgid "Get help"
msgstr "Ricevi aiuto"
#: albatrobot.py:194
msgid "Initializing..."
msgstr "Reimpostazione in corso..."
#: albatrobot.py:203
#: albatrobot.py:198
msgid "Done"
msgstr "Fatto"
#: albatrobot.py:228
#: albatrobot.py:217
msgid ""
"The only official version is the English one and any imperfect translation "
"would be misleading. Therefore, this document will not be translated."
msgstr ""
"L'unica versione ufficiale è quella inglese e qualunque traduzione "
"imperfetta sarebbe fuorviante. Pertanto, questo documento non sarà tradotto."
#: albatrobot.py:227
msgid "*Albatrobot's version:* {}"
msgstr "*Versione dell'Albatrobot:* {}"
#: albatrobot.py:242
#: albatrobot.py:240
msgid ""
"Christmas is good, but you can't invoke it so often! Try again in some "
"seconds..."
@ -222,22 +240,22 @@ msgstr ""
"Il Natale è bello, ma non puoi invocarlo così spesso! RIprova tra qualche "
"secondo..."
#: albatrobot.py:273
#: albatrobot.py:274
msgid ""
"Easter is good, but you can't invoke it so often! Retry in some seconds..."
msgstr ""
"La Pasqua è bella, ma non puoi invocarla così spesso! Riprova tra qualche "
"secondo..."
#: albatrobot.py:296
#: albatrobot.py:293
msgid "The most similar is {}."
msgstr "Il più simile è {}."
#: albatrobot.py:300
#: albatrobot.py:297
msgid "The most similar are {} and {}."
msgstr "I più simili sono {} e {}."
#: albatrobot.py:304
#: albatrobot.py:301
#, python-brace-format
msgid ""
"Author {required_author} is not present in the archive! {suggestion}\n"
@ -248,7 +266,7 @@ msgstr ""
"\n"
"N.b.: Le MaIuScOlE sOnO iMpOrTaNtI!"
#: albatrobot.py:324 albatrobot.py:352
#: albatrobot.py:321 albatrobot.py:347
#, python-brace-format
msgid ""
"{cit}\n"
@ -259,113 +277,118 @@ msgstr ""
"\n"
"~{author}"
#: albatrobot.py:345
#: albatrobot.py:340
msgid "Hello there, here an end of year dinner offered by {}!"
msgstr "Ciao, ecco un cenone di fine anno offerta da {}!"
#: albatrobot.py:359
#: albatrobot.py:354
#, python-brace-format
msgid "End of year dinner of {cits_number} plates delvered to {dest}!"
msgstr "Cenone di fine anno di {cits_number} portate consegnato a {dest}!"
#: albatrobot.py:372
#: albatrobot.py:368
msgid "What should I say?"
msgstr "Cosa dovrei dire?"
#: albatrobot.py:402
#: albatrobot.py:391
#, python-brace-format
msgid "Voice message from {sender_name}."
msgstr "Messaggio vocale da {sender_name}."
#: albatrobot.py:416
msgid "add `n` to the roll"
msgstr "aggiungi `n` al tiro"
#: albatrobot.py:403
#: albatrobot.py:417
msgid "subtract `n` from the roll"
msgstr "sottrati `n` dal tiro"
#: albatrobot.py:404
#: albatrobot.py:418
msgid "multiply the roll by `n`"
msgstr "moltiplica il tiro per `n`"
#: albatrobot.py:405
#: albatrobot.py:419
msgid "divide the roll by `n`"
msgstr "dividi il tiro per `n`"
#: albatrobot.py:406
#: albatrobot.py:420
msgid "floor divide the roll by `n`"
msgstr "ottieni il quoto del tiro diviso per `n`"
#: albatrobot.py:407
#: albatrobot.py:421
msgid "exponentiate the roll to `n`"
msgstr "eleva il tiro alla potenza `n`"
#: albatrobot.py:408
#: albatrobot.py:422
msgid "keep highest `n` rolls \\(defaults to `1`\\)"
msgstr "tieni gli `n` tiri più alti \\(valore predefinito: `1`\\)"
#: albatrobot.py:409
#: albatrobot.py:423
msgid "keep lowest `n` rolls \\(defaults to `1`\\)"
msgstr "tieni gli `n` tiri più bassi \\(valore predefinito: `1`\\)"
#: albatrobot.py:410
#: albatrobot.py:424
msgid "drop highest `n` rolls \\(defaults to `1`\\)"
msgstr "scarta gli `n` tiri più alti \\(valore predefinito: `1`\\)"
#: albatrobot.py:411
#: albatrobot.py:425
msgid "drop lowest `n` rolls \\(defaults to `1`\\)"
msgstr "scarta gli `n` tiri più bassi \\(valore predefinito: `1`\\)"
#: albatrobot.py:412
#: albatrobot.py:426
msgid "explode rolls equal to `n` \\(defaults to die size\\)"
msgstr ""
"fai esplodere i tiri pari a `n` \\(valore predefinito: dimensione del dado\\)"
#: albatrobot.py:413
#: albatrobot.py:427
msgid "explode rolls lower than `n`"
msgstr "fai esplodere i tiri minori di `n`"
#: albatrobot.py:414
#: albatrobot.py:428
msgid "explode rolls higher than `n`"
msgstr "fai esplodere i tiri maggiori di `n`"
#: albatrobot.py:415
#: albatrobot.py:429
msgid "count failures as rolls lower than `n`"
msgstr "conta i fallimenti come i tiri minori di `n`"
#: albatrobot.py:416
#: albatrobot.py:430
msgid "count failures as rolls higher than `n`"
msgstr "conta i fallimenti come i tiri maggiori di `n`"
#: albatrobot.py:417
#: albatrobot.py:431
msgid "count successes as rolls lower than `n`"
msgstr "conta i successi come i tiri minori di `n`"
#: albatrobot.py:418
#: albatrobot.py:432
msgid "count successes as rolls higher than `n`"
msgstr "conta i successi come i tiri maggiori di `n`"
#: albatrobot.py:419
#: albatrobot.py:433
msgid "penetrate rolls equal to dice size"
msgstr "penetra i tiri pari alla dimensione del dado"
#: albatrobot.py:420
#: albatrobot.py:434
msgid "penetrate rolls lower than `n`"
msgstr "penetra i tiri minori di `n`"
#: albatrobot.py:421
#: albatrobot.py:435
msgid "penetrate rolls higher than `n`"
msgstr "penetra i tiri maggiori di `n`"
#: albatrobot.py:422
#: albatrobot.py:436
msgid "add `n` to each roll"
msgstr "aggiungi `n` a ogni tiro"
#: albatrobot.py:423
#: albatrobot.py:437
msgid "subtract `n` from each roll"
msgstr "sottrai `n` a ogni tiro"
#: albatrobot.py:424
#: albatrobot.py:438
msgid "multiply by `n` each roll"
msgstr "moltiplica ogni tiro per `n`"
#: albatrobot.py:425
#: albatrobot.py:439
msgid ""
"reroll each dice that rolled `n` until there are no `n` left\\(defaults to "
"`1`\\)"
@ -373,12 +396,12 @@ msgstr ""
"ritira ogni dado con risultato `n` finché non ci sono `n` rimanenti "
"\\(valore predefinito: `1`\\)"
#: albatrobot.py:427
#: albatrobot.py:441
msgid "reroll once each dice that rolled `n` \\(defaults to 1\\)"
msgstr ""
"ritira una volta ogni dado che con risultato `n` \\(valore predefinito: 1\\)"
#: albatrobot.py:429
#: albatrobot.py:443
msgid ""
"reroll dice that rolled lower than `n` until there are no results lower than "
"`n` left"
@ -386,7 +409,7 @@ msgstr ""
"ritira i dadi con risultato minore di `n` finché non ci sono risultati "
"minori di `n` rimanenti"
#: albatrobot.py:431
#: albatrobot.py:445
msgid ""
"reroll dice that rolled higher than `n` until there no results higher than "
"`n` left"
@ -394,15 +417,15 @@ msgstr ""
"ritira i dadi con risultato maggiore di `n` finché non ci sono risultati "
"maggiori di `n` rimanenti"
#: albatrobot.py:433
#: albatrobot.py:447
msgid "reroll once dice that roll lower than `n`"
msgstr "ritira una volta i dadi con risultati minore di `n`"
#: albatrobot.py:434
#: albatrobot.py:448
msgid "reroll once dice that roll higher than `n`"
msgstr "ritira una volta i dadi con risultato maggiore di `n`"
#: albatrobot.py:439
#: albatrobot.py:453
msgid ""
"To roll, use the syntax `\\<number of dice\\>d\\<dice size\\>`\\. You can "
"also use the following modifiers\\. Note that:\n"
@ -421,15 +444,18 @@ msgstr ""
"\n"
"\n"
#: albatrobot.py:458
#: albatrobot.py:472
msgid "You can roll up to 500 dice with up to 500 faces at once!"
msgstr "Puoi tirare al massimo 1000 dadi con al massimo 1000 facce per volta!"
msgstr "Puoi tirare al massimo 500 dadi con al massimo 500 facce per volta!"
#: albatrobot.py:465
#: albatrobot.py:479
#, python-brace-format
msgid "{user_name} rolled {rolls} = {result}"
msgstr "{user_name} ha tirato {rolls} = {result}"
#: albatrobot.py:473
#: albatrobot.py:487
msgid "You used a wrong syntax!"
msgstr "Hai usato una sintassi errata!"
#~ msgid "Roll dice"
#~ msgstr "Tira dei dadi"

View File

@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Albatrobot 0.3\n"
"Project-Id-Version: Albatrobot v0.4.0-alpha\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-23 00:00+0000\n"
"POT-Creation-Date: 2023-06-11 00:00+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,55 +17,55 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: main.py:48 main.py:60 albatrobot.py:161
#: main.py:46 main.py:58 albatrobot.py:156
msgid "stop"
msgstr ""
#: main.py:48 main.py:69 albatrobot.py:159
#: main.py:46 main.py:67 albatrobot.py:154
msgid "init"
msgstr ""
#: main.py:65 albatrobot.py:143
#: main.py:63 albatrobot.py:139 albatrobot.py:191
msgid "help"
msgstr ""
#: main.py:73 albatrobot.py:144
#: main.py:71 albatrobot.py:140
msgid "legal"
msgstr ""
#: main.py:77 albatrobot.py:148
#: main.py:75 albatrobot.py:144
msgid "version"
msgstr ""
#: main.py:84 albatrobot.py:136
#: main.py:82 albatrobot.py:132 albatrobot.py:188
msgid "christmas"
msgstr ""
#: main.py:88 albatrobot.py:137
#: main.py:86 albatrobot.py:133 albatrobot.py:189
msgid "easter"
msgstr ""
#: main.py:92
#: main.py:90 albatrobot.py:190
msgid "end_of_year_dinner"
msgstr ""
#: main.py:96 albatrobot.py:141
#: main.py:94 albatrobot.py:137
msgid "epiphony"
msgstr ""
#: main.py:100 albatrobot.py:145 albatrobot.py:196
#: main.py:98 albatrobot.py:141
msgid "roll"
msgstr ""
#: albatrobot.py:81
#: albatrobot.py:77
msgid "User not authorized."
msgstr ""
#: albatrobot.py:89
#: albatrobot.py:85
msgid "Unknown command."
msgstr ""
#: albatrobot.py:103
#: albatrobot.py:99
msgid ""
"Hello, I'm Albatrobot\\! Type \\/help for help\\!\n"
"\n"
@ -76,140 +76,158 @@ msgid ""
"albatrobot)\\._"
msgstr ""
#: albatrobot.py:121
#: albatrobot.py:117
msgid "Albatrobot will be stopped in a few moments."
msgstr ""
#: albatrobot.py:134
#: albatrobot.py:130
msgid "*Albatrobot commands*"
msgstr ""
#: albatrobot.py:136
#: albatrobot.py:132
msgid "get an image"
msgstr ""
#: albatrobot.py:137
#: albatrobot.py:133
msgid " `\\(\\<author\\>\\)`"
msgstr ""
#: albatrobot.py:137
#: albatrobot.py:133
msgid ""
"get a citation from given author, or a random one if no author is "
"specified\\."
msgstr ""
#: albatrobot.py:139
#: albatrobot.py:135
msgid "end\\_of\\_year\\_dinner"
msgstr ""
#: albatrobot.py:139
#: albatrobot.py:135
msgid "send all citations in the archive to a random user\\."
msgstr ""
#: albatrobot.py:141
msgid " `\\(\\<text\\>\\)`"
#: albatrobot.py:137
msgid " `<text\\>`"
msgstr ""
#: albatrobot.py:141
#: albatrobot.py:137
msgid "get a voice message from Albatrobot reading given text"
msgstr ""
#: albatrobot.py:143
#: albatrobot.py:139
msgid "get help about bot commands\\."
msgstr ""
#: albatrobot.py:144
#: albatrobot.py:140
msgid "get legal info about privacy and copyright\\."
msgstr ""
#: albatrobot.py:145
#: albatrobot.py:141
msgid " `\\<dice\\>\\(\\<modifiers\\>\\)`"
msgstr ""
#: albatrobot.py:145
#: albatrobot.py:141
msgid ""
"roll dice, with or without modifiers\\. Launch without arguments to get help "
"on the modifiers\\."
msgstr ""
#: albatrobot.py:148
#: albatrobot.py:144
msgid "get Albatrobot's version"
msgstr ""
#: albatrobot.py:157
#: albatrobot.py:152
msgid "*Additional commands for bot admins*"
msgstr ""
#: albatrobot.py:159
#: albatrobot.py:154
msgid ""
"reinitialize the bot\\. This updates inline suggestions and purges /epiphony "
"cached files\\."
msgstr ""
#: albatrobot.py:161
#: albatrobot.py:156
msgid ""
"stop Albatrobot\\. To be used _only_ in case of emergency: restarting the "
"bot after this command is used requires direct access to the server\\."
msgstr ""
#: albatrobot.py:173
#: albatrobot.py:167
msgid ""
"Bot admins have access to additional commands and can get help on them "
"using /help in a private chat\\."
msgstr ""
#: albatrobot.py:182
#: albatrobot.py:174
#, python-brace-format
msgid ""
"{ccom_help}\n"
"{com_help}\n"
"\n"
"{acom_help}"
"{adm_help}"
msgstr ""
#: albatrobot.py:176
#, python-brace-format
msgid ""
"{com_help}\n"
"\n"
"{nonadm_addendum}"
msgstr ""
#: albatrobot.py:188
#, python-brace-format
msgid ""
"{ccom_help}\n"
"\n"
"{non_admin_addendum}"
msgid "Get an image"
msgstr ""
#: albatrobot.py:196
msgid "Roll dice"
#: albatrobot.py:189
msgid "Get a citation"
msgstr ""
#: albatrobot.py:199
#: albatrobot.py:190
msgid "Send all citations to a random user"
msgstr ""
#: albatrobot.py:191
msgid "Get help"
msgstr ""
#: albatrobot.py:194
msgid "Initializing..."
msgstr ""
#: albatrobot.py:203
#: albatrobot.py:198
msgid "Done"
msgstr ""
#: albatrobot.py:228
#: albatrobot.py:217
msgid ""
"The only official version is the English one and any imperfect translation "
"would be misleading. Therefore, this document will not be translated."
msgstr ""
#: albatrobot.py:227
msgid "*Albatrobot's version:* {}"
msgstr ""
#: albatrobot.py:242
#: albatrobot.py:240
msgid ""
"Christmas is good, but you can't invoke it so often! Try again in some "
"seconds..."
msgstr ""
#: albatrobot.py:273
#: albatrobot.py:274
msgid ""
"Easter is good, but you can't invoke it so often! Retry in some seconds..."
msgstr ""
#: albatrobot.py:296
#: albatrobot.py:293
msgid "The most similar is {}."
msgstr ""
#: albatrobot.py:300
#: albatrobot.py:297
msgid "The most similar are {} and {}."
msgstr ""
#: albatrobot.py:304
#: albatrobot.py:301
#, python-brace-format
msgid ""
"Author {required_author} is not present in the archive! {suggestion}\n"
@ -217,7 +235,7 @@ msgid ""
"N.b.: CaSe Is ImPoRtAnT!"
msgstr ""
#: albatrobot.py:324 albatrobot.py:352
#: albatrobot.py:321 albatrobot.py:347
#, python-brace-format
msgid ""
"{cit}\n"
@ -225,142 +243,147 @@ msgid ""
"~{author}"
msgstr ""
#: albatrobot.py:345
#: albatrobot.py:340
msgid "Hello there, here an end of year dinner offered by {}!"
msgstr ""
#: albatrobot.py:359
#: albatrobot.py:354
#, python-brace-format
msgid "End of year dinner of {cits_number} plates delvered to {dest}!"
msgstr ""
#: albatrobot.py:372
#: albatrobot.py:368
msgid "What should I say?"
msgstr ""
#: albatrobot.py:402
msgid "add `n` to the roll"
msgstr ""
#: albatrobot.py:403
msgid "subtract `n` from the roll"
msgstr ""
#: albatrobot.py:404
msgid "multiply the roll by `n`"
msgstr ""
#: albatrobot.py:405
msgid "divide the roll by `n`"
msgstr ""
#: albatrobot.py:406
msgid "floor divide the roll by `n`"
msgstr ""
#: albatrobot.py:407
msgid "exponentiate the roll to `n`"
msgstr ""
#: albatrobot.py:408
msgid "keep highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:409
msgid "keep lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:410
msgid "drop highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:411
msgid "drop lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:412
msgid "explode rolls equal to `n` \\(defaults to die size\\)"
msgstr ""
#: albatrobot.py:413
msgid "explode rolls lower than `n`"
msgstr ""
#: albatrobot.py:414
msgid "explode rolls higher than `n`"
msgstr ""
#: albatrobot.py:415
msgid "count failures as rolls lower than `n`"
#: albatrobot.py:391
#, python-brace-format
msgid "Voice message from {sender_name}."
msgstr ""
#: albatrobot.py:416
msgid "count failures as rolls higher than `n`"
msgid "add `n` to the roll"
msgstr ""
#: albatrobot.py:417
msgid "count successes as rolls lower than `n`"
msgid "subtract `n` from the roll"
msgstr ""
#: albatrobot.py:418
msgid "count successes as rolls higher than `n`"
msgid "multiply the roll by `n`"
msgstr ""
#: albatrobot.py:419
msgid "penetrate rolls equal to dice size"
msgid "divide the roll by `n`"
msgstr ""
#: albatrobot.py:420
msgid "penetrate rolls lower than `n`"
msgid "floor divide the roll by `n`"
msgstr ""
#: albatrobot.py:421
msgid "penetrate rolls higher than `n`"
msgid "exponentiate the roll to `n`"
msgstr ""
#: albatrobot.py:422
msgid "add `n` to each roll"
msgid "keep highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:423
msgid "subtract `n` from each roll"
msgid "keep lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:424
msgid "multiply by `n` each roll"
msgid "drop highest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:425
msgid "drop lowest `n` rolls \\(defaults to `1`\\)"
msgstr ""
#: albatrobot.py:426
msgid "explode rolls equal to `n` \\(defaults to die size\\)"
msgstr ""
#: albatrobot.py:427
msgid "explode rolls lower than `n`"
msgstr ""
#: albatrobot.py:428
msgid "explode rolls higher than `n`"
msgstr ""
#: albatrobot.py:429
msgid "count failures as rolls lower than `n`"
msgstr ""
#: albatrobot.py:430
msgid "count failures as rolls higher than `n`"
msgstr ""
#: albatrobot.py:431
msgid "count successes as rolls lower than `n`"
msgstr ""
#: albatrobot.py:432
msgid "count successes as rolls higher than `n`"
msgstr ""
#: albatrobot.py:433
msgid "penetrate rolls equal to dice size"
msgstr ""
#: albatrobot.py:434
msgid "penetrate rolls lower than `n`"
msgstr ""
#: albatrobot.py:435
msgid "penetrate rolls higher than `n`"
msgstr ""
#: albatrobot.py:436
msgid "add `n` to each roll"
msgstr ""
#: albatrobot.py:437
msgid "subtract `n` from each roll"
msgstr ""
#: albatrobot.py:438
msgid "multiply by `n` each roll"
msgstr ""
#: albatrobot.py:439
msgid ""
"reroll each dice that rolled `n` until there are no `n` left\\(defaults to "
"`1`\\)"
msgstr ""
#: albatrobot.py:427
#: albatrobot.py:441
msgid "reroll once each dice that rolled `n` \\(defaults to 1\\)"
msgstr ""
#: albatrobot.py:429
#: albatrobot.py:443
msgid ""
"reroll dice that rolled lower than `n` until there are no results lower than "
"`n` left"
msgstr ""
#: albatrobot.py:431
#: albatrobot.py:445
msgid ""
"reroll dice that rolled higher than `n` until there no results higher than "
"`n` left"
msgstr ""
#: albatrobot.py:433
#: albatrobot.py:447
msgid "reroll once dice that roll lower than `n`"
msgstr ""
#: albatrobot.py:434
#: albatrobot.py:448
msgid "reroll once dice that roll higher than `n`"
msgstr ""
#: albatrobot.py:439
#: albatrobot.py:453
msgid ""
"To roll, use the syntax `\\<number of dice\\>d\\<dice size\\>`\\. You can "
"also use the following modifiers\\. Note that:\n"
@ -372,15 +395,15 @@ msgid ""
"\n"
msgstr ""
#: albatrobot.py:458
#: albatrobot.py:472
msgid "You can roll up to 500 dice with up to 500 faces at once!"
msgstr ""
#: albatrobot.py:465
#: albatrobot.py:479
#, python-brace-format
msgid "{user_name} rolled {rolls} = {result}"
msgstr ""
#: albatrobot.py:473
#: albatrobot.py:487
msgid "You used a wrong syntax!"
msgstr ""

40
main.py
View File

@ -1,23 +1,21 @@
#!/bin/python3
"""
Albatrobot - Telegram bot for RPG groups and similar
Copyright (C) 2019, 2020, 2021, 2022 bursa-pastoris
This file is part of Albatrobot.
Albatrobot is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
Albatrobot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Albatrobot. If not, see <https://www.gnu.org/licenses/>.
"""
# Albatrobot - Telegram bot for RPG groups and similar
# Copyright (C) 2019, 2020, 2021, 2022, 2023 bursa-pastoris
#
# This file is part of Albatrobot.
#
# Albatrobot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Albatrobot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Albatrobot. If not, see <https://www.gnu.org/licenses/>.
import gettext
from telegram import Update
@ -45,7 +43,7 @@ application.add_handler(
albatrobot.unauthorized_user)
)
application.add_handler(
CommandHandler(['stop',_('stop'),'init',_('init')],
CommandHandler(['stop',_('stop'),'reset',_('reset')],
albatrobot.unauthorized_user,
(~filters.User(ADMINS)))
)
@ -66,8 +64,8 @@ application.add_handler(
albatrobot.help)
)
application.add_handler(
CommandHandler(['init',_('init')],
albatrobot.init)
CommandHandler(['reset',_('reset')],
albatrobot.reset)
)
application.add_handler(
CommandHandler(['legal',_('legal')],

View File

@ -1,6 +1,6 @@
python-telegram-bot[socks]~=20.0
python-telegram-bot[socks]~=20.3
Levenshtein~=0.21
psutil~=5.9
py-rolldice~=0.4
python-Levenshtein~=0.12
pyttsx3~=2.90

View File

@ -1,3 +1,2 @@
ID,author,text,year,place
ABT-0001,Albatrobot,No citations available,2022,
ABT-0002,Albatrobot,"No citations available, I said!",,Brescia
ID,author,text
ABT-0001,Albatrobot,No citations available

1 ID author text year place
2 ABT-0001 Albatrobot No citations available 2022
ABT-0002 Albatrobot No citations available, I said! Brescia

2
resources/imgs/imgs.csv Normal file
View File

@ -0,0 +1,2 @@
filename,caption
no-images-available.png,No images available
1 filename caption
2 no-images-available.png No images available

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -7,10 +7,11 @@ Admins:
[Settings]
Language:
MsgCooldown: 5
ChristmasCooldown: 5
EasterCooldown: 5
Proxy:
YellLang:
YellSpeed: 120
EpiphonyLang:
EpiphonySpeed: 120
[Resources]
CitArchive: resources/citations/citations.csv