Compare commits

..

65 Commits

Author SHA1 Message Date
palmtree5
9f4a7f7623 [V3] Bump version to 3.0.0b11 (#1483) 2018-04-02 17:19:50 -08:00
retke
10012c1e16 [V3] added --version flag (#1479) 2018-04-02 17:17:19 -08:00
Michael H
d65f8856f4 [V3] Data Converter (#1293)
* More docstrings

* still not ready...

* push this untested pile of code.

* working, menu needs cleaning up though, modlog converter not here yet

* menu cleanup

* add note about the fact that values are overwritten

* add i18n

* User friendlier quitting

* Better naming of a function

* setup automodule for dataconverter

* More documentation

* use Config.MEMBER (etc) instead of 'MEMBER' (etc)
2018-04-02 21:14:37 -04:00
Will
d79d8fbbea [V3] Fix logic issue with [p]load (#1460) 2018-04-02 17:09:17 -08:00
palmtree5
772590c41c [V3] Add settings displays to [p]set and [p]bankset (#1475) 2018-04-02 21:01:43 -04:00
aikaterna
d9c71bddb8 [V3 Audio] Add voteskip and DJ role (#1473)
* [V3 Audio] Add voteskip and DJ role

* Fix connection time storage for audiostats

* Update pause command for more explicit handling

Partially fixes #1478. Users will need to use pause twice before resuming until issue no. 20 on the Red-Lavalink repo is addressed.

* Update pause command

* Update pause command

* Add jukebox mode

Adds a price option for enqueuing songs. If DJ mode is active when jukebox mode is active, no one is charged credits as mods are exempt and plebs can't queue songs without the DJ role.
2018-04-02 20:53:37 -04:00
Will
29ce2401ca [V3 Config] Fix unloading and implement singleton driver (#1458)
* Add the identifier as an initialization parameter

* Remove config object singleton and opt for a shared JSON datastore

* Fix bot unloading to deal with memory leaks

* Fix tests

* Fix clear all bug
2018-04-02 16:47:27 -08:00
Will
720ef38886 [V3 Help] Fix the two missing characters in help (#1456) 2018-04-02 16:29:44 -08:00
Will
728ab6c8c1 [V3 Downloader] Allow for requiring minimum python version (#1455) 2018-04-02 16:26:07 -08:00
Will
935028addc [V3 Downloader] Add install messages from info.json (#1453) 2018-04-02 16:23:55 -08:00
palmtree5
e70e22d557 [V3 Image] Actually check if a client ID is set before making request (#1485)
* [V3 Image] actually check if a client id is set before making request

* Clarify imgurcreds docstring + drop guild_only from [p]imgur

* Fix the actual problem (bad urls)

* needs to be params not data
2018-04-02 20:14:16 -04:00
palmtree5
f3db4b5cb0 [V3 Modlog] Fix TypeError related to 'until' (#1487) 2018-04-02 20:09:09 -04:00
palmtree5
d60fc06379 [V3] Update translations from Crowdin (#1490) 2018-04-02 19:39:07 -04:00
Wyn
a813260717 [V3 Audio] Bump timeout connecting to Lavalink (#1474)
* [V3 Audio] Bump timeout connecting to Lavalink

Lavalink server can take 20-35 seconds to start, bumped to 50 seconds for good measure.

* Update audio.py

Added proper timeout

* Update __init__.py

Removed old timeout
2018-04-02 19:36:26 -04:00
bobloy
10d01df7dd [V3 General] Text fix in flip command (#1489) 2018-04-02 12:43:11 -08:00
palmtree5
8eb075fa86 [V3 Core] Embed toggling support (#1467)
* [V3 CogManagerUI] implement text-only support in [p]cogs

* Change page length to 1800 + workaround for pages starting with delim

* [V3 Core] text mode support for [p]contact and [p]dm

* Implement text-only support in modlog and fix everything that broke because of it

* Fix modlog stuff in filter too

* Fix tests

* Implement optional embed support in [p]help

* move to .format
2018-03-28 20:15:51 -04:00
palmtree5
c2e7bfa641 [V3 Instance setup] Implement backup support for instances using Mongo (#1470)
* [V3 Instance setup] import backup support for instances using Mongo

* remove_instance is now a coroutine + remove NIE

* move Mongo import down

* move another import
2018-03-28 20:12:26 -04:00
palmtree5
2f23244937 [V3 Core] Add [p]backup (#1471)
* [V3 Core] add [p]backup

* move imports
2018-03-28 19:53:27 -04:00
palmtree5
9ecea9e1d5 [V3 instance setup] Warn and request confirmation if instance name already in use (#1469) 2018-03-28 19:13:34 -04:00
palmtree5
61b34e835e [V3] Drop an unnecessary if in embed_requested (#1468) 2018-03-28 19:10:02 -04:00
palmtree5
4e2b83c052 [V3 Docs] Add and update existing features (#1451)
* [V3 Docs] bump version

* Remove removed functions from __all__

* Update docstring format

* Update copyright year

* Add embed utils docs

* Document bot class

* Document RPC

* Update toctree
2018-03-24 17:27:04 -04:00
palmtree5
45ee4755a6 [V3 Core] Fix url sent when doing [p]invite (#1461) 2018-03-24 17:24:06 -04:00
palmtree5
59281afe90 [V3 Instance setup] cog identifiers are strings, not ints (#1448) 2018-03-22 19:11:27 -04:00
retke
cf5a63a5d5 [V3] Set token command fix (#1449)
* [V3] Add set token command

* DM check

* warning message + delete if token isn't send in DM

* Update string formatting

* fix condition invertion
2018-03-22 19:08:57 -04:00
Will
96869074c3 [V3 Docs] Third time's the charm (#1447)
* Get the right sphinx version

* Add mongo extra
2018-03-20 21:14:25 -04:00
Will
c107d5fa7f [V3 Docs] Really fix it this time (#1444) 2018-03-20 21:08:01 -04:00
Will
bed56e8891 [V3 Docs] Add new RTD yaml file (#1443) 2018-03-20 20:58:48 -04:00
palmtree5
c4b641e62a [V3] Bump version to 3.0.0b10 (#1418) 2018-03-20 16:36:32 -08:00
James
153d710eb4 [V3] Allow load, unload and reload to deal with multiple packages (#1441)
* [V3] Allow load, unload and reload to deal with multiple packages

This PR allows multiple packages to be loaded, unloaded or reloaded with the one command, the packages are delimited by the space character as suggested by Will
This is just the functionality, I'm sure the code could be better

* introduced helper function for getting package load strings

* missed characters

* forgotten import 👀

Forgot to include the import `inline` method from chat_formatting
2018-03-20 16:32:54 -08:00
palmtree5
83471e0866 [V3 Core] implement commands and settings for embeds (#1437)
* [V3 Core] add settings for whether to use embeds or not

* Implement commands to toggle embed settings

* Add a function to context for finding whether to use embeds or not

* Hide [p]embedset for now

* Move embed_requested to bot

* Add a simple helper in context
2018-03-21 01:17:40 +01:00
Michael H
01b9843883 [V3] Change presence (continued fixes) (#1438)
* This better fixes the root issue rather than attempting to work around it

* move bot_in_guild to checks, and use the correct syntax
2018-03-21 01:12:40 +01:00
retke
749af89e9f [V3] Set token command (#1425)
* [V3] Add set token command

* DM check

* warning message + delete if token isn't send in DM

* Update string formatting
2018-03-21 01:08:36 +01:00
palmtree5
27b61a2770 [V3 Streams] Fix community alerts (#1426)
* [V3 Streams] fix community alerts

* drop unneeded parentheses + delete messages when removing from cache

* move to one embed for a community

* fix adding image to embed

* Remove unneeded params

* Really helps to point to the right place

* drop the game, move channel name+link to value

* Use stream title in embeds

* Increase number of streams to grab to 100

* filter out streams with existing individual alerts in the channel

* need channel id, not stream id in filtering function

* sample from the list

* we only want to break out if the alert is a TwitchStream alert

* drop off sending the mentions if there are none
2018-03-20 19:25:23 -04:00
palmtree5
eb3b6346bb [V3] Set r/w access before deleting files (#1412)
* [V3] set access before deleting

* [V3] move+rename do_delete and use in repo removal in downloader
2018-03-20 18:46:15 -04:00
aikaterna
2e9a0de4a1 [V3 Audio] Update audio to use Red-Lavalink (#1440)
* [V3 Audio] Update audio for Red-Lavalink

* Update requirements for new library

* Fix logic for connect time storage for audiostats

Only store time when connecting to the voice channel.
2018-03-20 23:28:31 +01:00
palmtree5
f83e3cc3e7 [V3 Economy] Expand payday output (#1386)
* [V3 Economy] implement suggestions from #1371

* Fix a typo

* Add functions for getting leaderboard and leaderboard position

* Use the new functions to get leaderboard position and leaderboard (overrides https://github.com/Cog-Creators/Red-DiscordBot/pull/1435)

* Actually implement showing only guild members on leaderboard when bank is global

* get_leaderboard_position needs to be awaited

* For global bank, pass None for guild to get_leaderboard when trying to find position

* Remove some unneeded code

* Wrong index...

* Combine 3 messages into 1

* Fix guild leaderboard while bank is global

* add missing parentheses

* Modify the leaderboard formatting

* More work on leaderboard formatting

* no subtraction
2018-03-20 18:22:10 -04:00
palmtree5
a8f4659552 [V3 Instance Setup] Storage swapping (#1421)
* [V3 Instance Setup] start work on storage swapping

* This should do the trick for Mongo -> JSON

* Fix typo

* Fix a few more typos

* resolve the data path

* Upsert the imported data

* need a list of the documents

* to_list is a coro
2018-03-16 13:37:12 -08:00
Will
25a5c3dec9 Pip install to library dir (#1432) 2018-03-16 16:12:05 +01:00
Wyn
c49cb4a213 [V3 Readme] Update Patreon link (#1434)
Add on to #1431
2018-03-14 19:22:50 -04:00
palmtree5
c4dbbc2d1e [V3 Warnings] Action list isn't a dict (fix #1382) (#1408) 2018-03-14 19:10:07 -04:00
palmtree5
fe3d6f57af [V3 Streams] Add support for Youtube streams (#1385) 2018-03-14 19:07:14 -04:00
palmtree5
052af2f9bf [V3 Cleanup] Code consolidation (#1347)
* [V3 Cleanup] refactor to consolidate duplicate code

* [V3 Cleanup] make the prompting function a staticmethod

* Drop continuing message + add punctuation to docstrings
2018-03-14 19:03:11 -04:00
Adam
16da9f52ac [V3 Audio] update Lavalink build (#1427) 2018-03-12 21:48:13 -08:00
palmtree5
22a342d36d [V3 Bank/Economy] Fix #1404 and an issue with [p]bank reset (#1407)
* [V3 Bank] fix an issue with checks

* [V3 Economy] fix issues with [p]bank reset
2018-03-12 19:10:46 -04:00
palmtree5
4fcf32b5e9 [V3 Bank] Add confirmation prompt on [p]bankset toggleglobal (#1402) 2018-03-12 19:05:21 -04:00
palmtree5
5bdb455bc0 [V3 Instance setup] Change backup time separator for Windows (#1419) 2018-03-12 18:48:13 -04:00
BaIthamel
1cb74f0ea7 [V3] Fix for issue #1363 (#1424)
[p]cogs and [p]repo now print alphabetically
2018-03-12 18:44:30 -04:00
Tobotimus
c7e8c95640 [V3] discord.Game -> discord.Activity (#1397)
* [V3] discord.Game -> discord.Activity

* Update userinfo to reference new enum
2018-03-12 18:41:37 -04:00
Will
ccb322d08e [Audio] V3/auto autostart only (#1420)
* Download jar at audio load

* Messy...

* Remove leftover log file stuff

* Keep application.yml

* Damn you windows
2018-03-12 00:49:08 +01:00
Wyn
b27e0f2d21 [V3 Audio] Rename Game to Activity (#1409)
* Rename `Game` to `Activity` for audio

Add on to pull #1397

* Update audio.py

Whoops, don't need this here

* Update audio.py

Now fixed
2018-03-08 20:55:03 -05:00
aikaterna
6a715d87dd [V3 Audio] Add prev command, bugfixes for audiostats, search (#1405)
* Update audiostats to display days in timer

* Add prev command

* Update search button to play enqueued song
2018-03-08 20:50:54 -05:00
Tobotimus
6138b78c07 [V3 Admin] Make [p]announce consume all args into the message (#1394)
* Fix announce (resolves #1390)

* Make other commands consume all args

Also fixes [p]announce channel
2018-03-08 20:45:41 -05:00
palmtree5
f84ef48819 [V3 Docs] add java install to install docs (#1389) 2018-03-08 20:06:27 +01:00
palmtree5
cda27944b6 [V3 Mod] fix #1401 (#1403) 2018-03-07 09:48:22 +11:00
Will
c9281f734b [V3 Config] Fix clear throwing errors (#1374) 2018-03-06 10:28:37 +11:00
palmtree5
f378ea0d2e [V3 Core] add update check (#1388)
* [V3 Core] add update check

* [V3 Core] have it DM the owner if out of date
2018-03-06 10:21:01 +11:00
James
40c37b5c06 [V3 Help][ fix help_formatter to obey length limits (#1375)
Help didn't account for docstrings passing length limits which I noticed a while ago and as noticed again when Palm forgot a dual newline in a command docstring.
This PR sees to fix this by enforcing length limits on description, field names and field values
2018-03-06 10:10:56 +11:00
Will
57b7db6956 [V3 Admin] Remove guild default channel (#1381)
* Remove guild default channel

* Fix weird set thing
2018-03-06 09:52:26 +11:00
Michael H
b4f5c2c0a1 Revert "[V3]Encoding issue fix" (#1392)
* Revert "[V3 Core] Encoding issue fix (#1365)"

This reverts commit f6903cf582.

* Don't let the system encoding screw with things,
specify opens as happening with utf-8 encoding

(cherry picked from commit c10e4dddca)
2018-03-06 08:18:41 +11:00
Michael H
f6903cf582 [V3 Core] Encoding issue fix (#1365)
* Don't let the system encoding screw with things,
specify opens as happening with utf-8 encoding

* And also deal with encoding issues because windows is a special snowflake
(see: #1366)

* let's just use the encoding param in str() rather than encode/decode...
2018-03-04 13:02:04 -05:00
aikaterna
3816385228 [V3 Audio] Fix repeat, Message deletions (#1379)
* Fix repeat

Also remove restriction on if the player is playing.

* Auto-delete existing Now Playing message

* Auto-delete existing notify message

* Wrap line on Now Playing message

* Add connected duration to audiostats

_dynamic_time based on a function written by Redjumpman

* Return negative seek past song start as 00:00:00

* Version number
2018-03-03 18:55:24 -05:00
Will
f65085946c [V3 Audio] Initial V3 addition (#1373)
* Initial audio

* Add application data and modify port

* Modify codeowners

* Need extra newline

* add yml to manifest

* lock lavalink version
2018-03-03 15:42:20 +11:00
Thomas Mercurio
b10b746d9e [V3 Config] Correct Mongo connection URI without credentials (#1362)
* Correct connection string without credentials

* Remove extra whitespace.
2018-03-02 18:39:45 +01:00
James
ed5945e182 fixed exception (#1372)
`requirements.remove` will raise a ValueError if the item is not there, not `IndexError`
2018-03-02 18:35:28 +01:00
Will
cf48a13fc7 Potentially fix auto deploy issues (#1357) 2018-02-28 13:08:47 +01:00
167 changed files with 4219 additions and 1367 deletions

4
.github/CODEOWNERS vendored
View File

@@ -21,11 +21,12 @@ redbot/core/rpc.py @tekulvw
redbot/core/sentry_setup.py @Kowlin @tekulvw
redbot/core/utils/chat_formatting.py @tekulvw
redbot/core/utils/mod.py @palmtree5
redbot/core/utils/data_converter.py @mikeshardmind
# Cogs
redbot/cogs/admin/* @tekulvw
redbot/cogs/alias/* @tekulvw
redbot/cogs/audio/* @tekulvw
redbot/cogs/audio/* @aikaterna @atiwiex
redbot/cogs/bank/* @tekulvw
redbot/cogs/cleanup/* @palmtree5
redbot/cogs/customcom/* @palmtree5
@@ -38,6 +39,7 @@ redbot/cogs/mod/* @palmtree5
redbot/cogs/modlog/* @palmtree5
redbot/cogs/streams/* @Twentysix26 @palmtree5
redbot/cogs/trivia/* @Tobotimus
redbot/cogs/dataconverter/* @mikeshardmind
# Docs
docs/* @tekulvw @palmtree5

14
.readthedocs.yml Normal file
View File

@@ -0,0 +1,14 @@
formats:
- pdf
build:
image: latest
requirements_file: docs/requirements.txt
python:
version: 3.6
pip_install: true
extra_requirements:
- docs
- mongo

View File

@@ -8,11 +8,9 @@ python:
- 3.5.3
- 3.6.1
install:
- echo "pytest>3" >> requirements.txt
- echo "pytest-asyncio" >> requirements.txt
- echo "git+https://github.com/Rapptz/discord.py.git@rewrite#egg=discord.py[voice]" >> requirements.txt
- pip install -r requirements.txt
- pip install .
- pip install .[test]
script:
- python -m compileall ./redbot/cogs
- python -m pytest

View File

@@ -2,3 +2,4 @@ include README.rst
include LICENSE
include requirements.txt
include discord/bin/*.dll
include redbot/cogs/audio/application.yml

View File

@@ -10,6 +10,10 @@
:target: https://crowdin.com/project/red-discordbot
:alt: Crowdin
.. image:: https://img.shields.io/badge/Support-Red!-orange.svg
:target: https://www.patreon.com/Red_Devs
:alt: Patreon
********************
Red - Discord Bot v3
********************

View File

@@ -0,0 +1,62 @@
.. Importing data from a V2 install
================================
Importing data from a V2 install
================================
----------------
What you'll need
----------------
1. A Running V3 bot
2. The path where your V2 bot is installed
--------------
Importing data
--------------
.. important::
Unless otherwise specified, the V2 data will take priority over V3 data for the same entires
.. important::
For the purposes of this guide, your prefix will be denoted as
[p]
You should swap whatever you made your prefix in for this.
All of the below are commands to be entered in discord where the bot can
see them.
The dataconverter cog is not loaded by default. To start, load it with
.. code-block:: none
[p]load dataconverter
Next, you'll need to give it the path where your V2 install is.
On linux and OSX, it may look something like:
.. code-block:: none
/home/username/Red-DiscordBot/
On Windows it will look something like:
.. code-block:: none
C:\Users\yourusername\Red-DiscordBot
Once you have that path, give it to the bot with the following command
(make sure to swap your own path in)
.. code-block:: none
[p]convertdata /home/username/Red-DiscordBot/
From here, if the path is correct, you will be prompted with an interactive menu asking you
what data you would like to import
You can select an entry by number, or quit with any of 'quit', 'exit', 'q', '-1', or 'cancel'

View File

@@ -55,7 +55,7 @@ master_doc = 'index'
# General information about the project.
project = 'Red - Discord Bot'
copyright = '2017, Cog Creators'
copyright = '2018, Cog Creators'
author = 'Cog Creators'
# The version info for the project you're documenting, acts as replacement for
@@ -63,9 +63,9 @@ author = 'Cog Creators'
# built documents.
#
# The short X.Y version.
version = '3.0.0a1'
version = '3.0.0b11'
# The full version, including alpha/beta/rc tags.
release = '3.0.0a1'
release = '3.0.0b11'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

19
docs/framework_bot.rst Normal file
View File

@@ -0,0 +1,19 @@
.. bot module docs
===
Bot
===
.. automodule:: redbot.core.bot
RedBase
^^^^^^^
.. autoclass:: RedBase
:members:
Red
^^^
.. autoclass:: Red
:members:

8
docs/framework_rpc.rst Normal file
View File

@@ -0,0 +1,8 @@
.. rpc docs
===
RPC
===
.. automodule:: redbot.core.rpc
:members:

View File

@@ -10,8 +10,20 @@ Chat Formatting
.. automodule:: redbot.core.utils.chat_formatting
:members:
Embed Helpers
=============
.. automodule:: redbot.core.utils.embed
:members:
Mod Helpers
===========
.. automodule:: redbot.core.utils.mod
:members:
V2 Data Conversion
==================
.. automodule:: redbot.core.utils.data_converter
:members: DataConverter

View File

@@ -0,0 +1,154 @@
.. Converting Data from a V2 cog
.. role:: python(code)
:language: python
============================
Importing Data From a V2 Cog
============================
This guide serves as a tutorial on using the DataConverter class
to import settings from a V2 cog.
------------------
Things you'll need
------------------
1. The path where each file holding related settings in v2 is
2. A conversion function to take the data and transform it to conform to Config
-----------------------
Getting your file paths
-----------------------
You should probably not try to find the files manually.
Asking the user for the base install path and using a relative path to where the
data should be, then testing that the file exists there is safer. This is especially
True if your cog has multiple settings files
Example
.. code-block:: python
from discord.ext import commands
from pathlib import Path
@commands.command(name="filefinder")
async def file_finding_command(self, ctx, filepath):
"""
this finds a file based on a user provided input and a known relative path
"""
base_path = Path(filepath)
fp = base_path / 'data' / 'mycog' / 'settings.json'
if not fp.is_file():
pass
# fail, prompting user
else:
pass
# do something with the file
---------------
Converting data
---------------
Once you've gotten your v2 settings file, you'll want to be able to import it
There are a couple options available depending on how you would like to convert
the data.
The first one takes a data path, and a conversion function and does the rest for you.
This is great for simple data that just needs to quickly be imported without much
modification.
Here's an example of that in use:
.. code-block:: python
from pathlib import Path
from discord.ext import commands
from redbot.core.utils.data_converter import DataConverter as dc
from redbot.core.config import Config
...
async def import_v2(self, file_path: Path):
"""
to be called from a command limited to owner
This should be a coroutine as the convert function will
need to be awaited
"""
# First we give the converter out cog's Config instance.
converter = dc(self.config)
# next we design a way to get all of the data into Config's internal
# format. This should be a generator, but you can also return a single
# list with identical results outside of memory usage
def conversion_spec(v2data):
for guild_id in v2.data.keys():
yield {(Config.GUILD, guild_id): {('blacklisted',): True}}
# This is yielding a dictionary that is designed for config's set_raw.
# The keys should be a tuple of Config scopes + the needed Identifiers. The
# values should be another dictionary whose keys are tuples representing
# config settings, the value should be the value to set for that.
# Then we pass the file and the conversion function
await converter.convert(file_path, conversion_spec)
# From here, our data should be imported
You can also choose to convert all of your data and pass it as a single dict
This can be useful if you want finer control over the dataconversion or want to
preserve any data from v3 that may share the same entry and set it aside to prompt
a user
.. code-block:: python
from pathlib import Path
from discord.ext import commands
from redbot.core.utils.data_converter import DataConverter as dc
from redbot.core.config import Config
...
await dc(config_instance).dict_import(some_processed_dict)
The format of the items of the dict is the same as in the above example
-----------------------------------
Config Scopes and their Identifiers
-----------------------------------
This section is provided as a quick reference for the identifiers for default
scopes available in Config. This does not cover usage of custom scopes, though the
data converter is compatible with those as well.
Global::
:code:`(Config.GLOBAL,)`
Guild::
:code:`(Config.GUILD, guild_id)`
Channel::
:code:`(Config.CHANNEL, channel_id)`
User::
:code:`(Config.USER, user_id)`
Member::
:code:`(Config.MEMBER, guild_id, user_id)`
Role::
:code:`(Config.ROLE, role_id)`
-----------------------------
More information and Examples
-----------------------------
For a more in depth look at how all of these commands function
You may want to take a look at how core data is being imported
:code:`redbot/cogs/dataconverter/core_specs.py`

View File

@@ -16,6 +16,7 @@ Welcome to Red - Discord Bot's documentation!
install_debian
install_centos
install_raspbian
cog_dataconverter
.. toctree::
:maxdepth: 2
@@ -29,14 +30,18 @@ Welcome to Red - Discord Bot's documentation!
guide_migration
guide_cog_creation
guide_data_conversion
framework_bank
framework_bot
framework_cogmanager
framework_datamanager
framework_config
framework_context
framework_datamanager
framework_downloader
framework_events
framework_i18n
framework_modlog
framework_context
framework_rpc
framework_utils

View File

@@ -12,7 +12,7 @@ Installing pre-requirements
yum -y groupinstall development
yum -y install https://centos7.iuscommunity.org/ius-release.rpm
yum -y install yum-utils wget which python35u python35u-pip python35u-devel openssl-devel libffi-devel git opus-devel
yum -y install yum-utils wget which python35u python35u-pip python35u-devel openssl-devel libffi-devel git opus-devel java-1.8.0-openjdk
sh -c "$(wget https://gist.githubusercontent.com/mustafaturan/7053900/raw/27f4c8bad3ee2bb0027a1a52dc8501bf1e53b270/latest-ffmpeg-centos6.sh -O -)"
--------------

View File

@@ -14,7 +14,7 @@ Installing pre-requirements
echo "deb http://httpredir.debian.org/debian stretch-backports main contrib non-free" >> /etc/apt/sources.list
apt-get update
apt-get install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git ffmpeg libopus-dev unzip -y
apt-get install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git ffmpeg libopus-dev unzip default-jre -y
------------------
Installing the bot

View File

@@ -17,6 +17,8 @@ Installing pre-requirements
* :code:`brew install git`
* :code:`brew install ffmpeg --with-ffplay`
* :code:`brew install opus`
* :code:`brew tap caskroom/versions`
* :code:`brew cask install java8`
--------------
Installing Red

View File

@@ -10,7 +10,7 @@ Installing pre-requirements
.. code-block:: none
sudo apt-get install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git libav-tools libopus-dev unzip -y
sudo apt-get install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git libav-tools libopus-dev unzip default-jre -y
--------------
Installing Red

View File

@@ -12,7 +12,7 @@ Installing the pre-requirements
.. code-block:: none
sudo apt install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git ffmpeg libopus-dev unzip -y
sudo apt install python3.5-dev python3-pip build-essential libssl-dev libffi-dev git ffmpeg libopus-dev unzip default-jre -y
------------------
Installing the bot

View File

@@ -21,6 +21,10 @@ Needed Software
.. attention:: Please choose the option to "Run Git from the Windows Command Prompt" in Git's setup
* `Java <https://java.com/en/download/manual.jsp>`_ - needed for Audio
.. attention:: Please choose the "Windows Online" installer
--------------
Installing Red
--------------

View File

@@ -1,4 +1,4 @@
sphinx==1.6.3
sphinx==1.6.5
sphinxcontrib-asyncio
sphinx_rtd_theme
git+https://github.com/Rapptz/discord.py@rewrite#egg=discord.py[voice]

View File

@@ -96,15 +96,18 @@ def list_instances():
def main():
description = "Red - Version {}".format(__version__)
cli_flags = parse_cli_flags(sys.argv[1:])
if cli_flags.list_instances:
list_instances()
elif cli_flags.version:
print(description)
sys.exit(0)
elif not cli_flags.instance_name:
print("Error: No instance name was provided!")
sys.exit(1)
load_basic_configuration(cli_flags.instance_name)
log, sentry_log = init_loggers(cli_flags)
description = "Red - Version {}".format(__version__)
red = Red(cli_flags, description=description, pm_help=None)
init_global_checks(red)
init_events(red, cli_flags)

View File

@@ -134,7 +134,7 @@ class Admin:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(manage_roles=True)
async def addrole(self, ctx: commands.Context, rolename: discord.Role,
async def addrole(self, ctx: commands.Context, rolename: discord.Role, *,
user: MemberDefaultAuthor=None):
"""
Adds a role to a user. If user is left blank it defaults to the
@@ -151,7 +151,7 @@ class Admin:
@commands.command()
@commands.guild_only()
@checks.admin_or_permissions(manage_roles=True)
async def removerole(self, ctx: commands.Context, rolename: discord.Role,
async def removerole(self, ctx: commands.Context, rolename: discord.Role, *,
user: MemberDefaultAuthor=None):
"""
Removes a role from a user. If user is left blank it defaults to the
@@ -227,7 +227,7 @@ class Admin:
@commands.group(invoke_without_command=True)
@checks.is_owner()
async def announce(self, ctx: commands.Context, message: str):
async def announce(self, ctx: commands.Context, *, message: str):
"""
Announces a message to all servers the bot is in.
"""
@@ -259,13 +259,13 @@ class Admin:
@announce.command(name="channel")
@commands.guild_only()
@checks.guildowner_or_permissions(administrator=True)
async def announce_channel(self, ctx, channel: discord.TextChannel=None):
async def announce_channel(self, ctx, *, channel: discord.TextChannel=None):
"""
Changes the channel on which the bot makes announcements.
"""
if channel is None:
channel = ctx.channel
await self.conf.guild(ctx.guild).set("announce_channel", channel.id)
await self.conf.guild(ctx.guild).announce_channel.set(channel.id)
await ctx.send("The announcement channel has been set to {}".format(
channel.mention
@@ -274,7 +274,7 @@ class Admin:
@announce.command(name="ignore")
@commands.guild_only()
@checks.guildowner_or_permissions(administrator=True)
async def announce_ignore(self, ctx, guild: discord.Guild=None):
async def announce_ignore(self, ctx, *, guild: discord.Guild=None):
"""
Toggles whether the announcements will ignore the given server.
Defaults to the current server if none is provided.
@@ -310,7 +310,7 @@ class Admin:
return valid_roles
@commands.group(invoke_without_command=True)
async def selfrole(self, ctx: commands.Context, selfrole: SelfRole):
async def selfrole(self, ctx: commands.Context, *, selfrole: SelfRole):
"""
Add a role to yourself that server admins have configured as
user settable.
@@ -319,7 +319,7 @@ class Admin:
await self._addrole(ctx, ctx.author, selfrole)
@selfrole.command(name="remove")
async def selfrole_remove(self, ctx: commands.Context, selfrole: SelfRole):
async def selfrole_remove(self, ctx: commands.Context, *, selfrole: SelfRole):
"""
Removes a selfrole from yourself.
"""
@@ -328,7 +328,7 @@ class Admin:
@selfrole.command(name="add")
@commands.has_permissions(manage_roles=True)
async def selfrole_add(self, ctx: commands.Context, role: discord.Role):
async def selfrole_add(self, ctx: commands.Context, *, role: discord.Role):
"""
Add a role to the list of available selfroles.
"""
@@ -340,7 +340,7 @@ class Admin:
@selfrole.command(name="delete")
@commands.has_permissions(manage_roles=True)
async def selfrole_delete(self, ctx: commands.Context, role: SelfRole):
async def selfrole_delete(self, ctx: commands.Context, *, role: SelfRole):
"""
Removes a role from the list of available selfroles.
"""

View File

@@ -43,7 +43,10 @@ class Announcer:
channel = guild.get_channel(channel_id)
if channel is None:
channel = guild.default_channel
channel = guild.system_channel
if channel is None:
channel = guild.text_channels[0]
return channel

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"
@@ -22,15 +22,15 @@ msgstr "Arrr, no prefix found capt'n!"
#: ../alias.py:198
msgid "You attempted to create a new alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Ye try and make a squeeky-clean alias with the name {} but 'she be taken by another order."
#: ../alias.py:205
msgid "You attempted to create a new alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Ye try and make a Squeeky-clean alias with the name {} but 'she already be on the island."
#: ../alias.py:212
msgid "You attempted to create a new alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Ye try and make a Squeeky-clean alias with the name {} but 'she walk the plank! Spaces in an alias must walk the plank."
#: ../alias.py:224
msgid "A new alias with the trigger `{}` has been created."
@@ -38,15 +38,15 @@ msgstr "Arrr! A new alias with thee trigger `{}` has been created."
#: ../alias.py:236
msgid "You attempted to create a new global alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Ye try and make a squeeky-clean global alias with the name {} but 'she be taken by another order."
#: ../alias.py:243
msgid "You attempted to create a new global alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Ye try and make a Squeeky-clean global alias with the name {} but 'she already be on the island."
#: ../alias.py:250
msgid "You attempted to create a new global alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Ye try and make a Squeeky-clean global alias with the name {} but 'she walk the plank! Spaces in an alias must walk the plank."
#: ../alias.py:259
msgid "A new global alias with the trigger `{}` has been created."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -22,15 +22,15 @@ msgstr "Awalan tidak ditemukan."
#: ../alias.py:198
msgid "You attempted to create a new alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias baru dengan nama {} tetapi nama itu sudah menjadi perintah pada bot ini."
#: ../alias.py:205
msgid "You attempted to create a new alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias baru dengan nama {} tetapi alias itu sudah ada pada server ini."
#: ../alias.py:212
msgid "You attempted to create a new alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias baru dengan nama {} tetapi nama itu adalah sebuah nama alias yang tidak berlaku. Nama alias tidak boleh berisi spasi."
#: ../alias.py:224
msgid "A new alias with the trigger `{}` has been created."
@@ -38,15 +38,15 @@ msgstr "Alias baru dengan pemicu '{}' telah dibuat."
#: ../alias.py:236
msgid "You attempted to create a new global alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias global baru dengan nama {} tetapi nama itu sudah menjadi sebuah perintah pada bot ini."
#: ../alias.py:243
msgid "You attempted to create a new global alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias global baru dengan nama {} tetapi alias itu sudah ada pada server ini."
#: ../alias.py:250
msgid "You attempted to create a new global alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Anda mencoba untuk membuat sebuah alias global baru dengan nama {} tetapi nama itu adalah sebuah nama alias yang tidak berlaku. Nama alias tidak boleh berisi spasi."
#: ../alias.py:259
msgid "A new global alias with the trigger `{}` has been created."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,73 +18,73 @@ msgstr ""
#: ../alias.py:129
msgid "No prefix found."
msgstr "접두사가 발견되지 않았습니다."
msgstr "프리픽스를 찾을 수 없어요."
#: ../alias.py:198
msgid "You attempted to create a new alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "이름이 {} 인 바로가기를 만들려고 했지만, 이 봇의 커맨드와 중복돼요."
#: ../alias.py:205
msgid "You attempted to create a new alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "이름이 {} 인 바로가기를 만들려고 했지만, 해당 바로가기가 이미 이 서버에 등록되어 있어요."
#: ../alias.py:212
msgid "You attempted to create a new alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "이름이 {} 인 바로가기를 만들려고 했지만, 잘못된 바로가기 이름에요. 바로가기 이름에는 공백이 포함될 수 없어요."
#: ../alias.py:224
msgid "A new alias with the trigger `{}` has been created."
msgstr "`{}`로 발동되는 바로가기가 생성되었습니다."
msgstr "트리거 `{}` 이(가) 포함된 별칭이 등록됐어요."
#: ../alias.py:236
msgid "You attempted to create a new global alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "이름이 {} 인 글로벌 별칭을 만들려고 했지만, 이 봇의 커맨드와 중복돼요."
#: ../alias.py:243
msgid "You attempted to create a new global alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "이름이 {} 인 글로벌 별칭을 만들려고 했지만, 해당 별칭이 이미 이 서버에 등록되어 있어요."
#: ../alias.py:250
msgid "You attempted to create a new global alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "이름이 {} 인 글로벌 별칭을 만들려고 했지만, 잘못된 별칭 이름에요. 별칭 이름에는 공백이 포함될 수 없어요."
#: ../alias.py:259
msgid "A new global alias with the trigger `{}` has been created."
msgstr "`{}`로 발동되는 전역 바로가기가 생성 되었습니다."
msgstr "트리거 `{}` 이(가) 포함된 글로벌 별칭이 등록됐어요."
#: ../alias.py:274
msgid "No such alias exists."
msgstr "해당 바로가기가 없습니다."
msgstr "그런 별칭은 등록되어 있지 않아요."
#: ../alias.py:283
msgid "The `{}` alias will execute the command `{}`"
msgstr "바로가기 `{}`는 명령어 `{}` 를 실행 합니다."
msgstr "`{}` 별칭이 `{}` 커맨드를 실행했어요."
#: ../alias.py:286
msgid "There is no alias with the name `{}`"
msgstr "`{}`로 지정된 바로가기가 없습니다."
msgstr "`{}` 이란 이름으로 등록된 별칭이 없어요."
#: ../alias.py:298
msgid "There are no aliases on this guild."
msgstr "이 길드에는 바로가기가 없습니다."
msgstr "이 길드에 등록된 별칭이 없어요."
#: ../alias.py:302 ../alias.py:320
msgid "Alias with the name `{}` was successfully deleted."
msgstr "바로가기 `{}` 성공적으로 삭제 되었습니다."
msgstr "별칭 `{}` 이(가) 성공적으로 삭제됐어요."
#: ../alias.py:305 ../alias.py:323
msgid "Alias with name `{}` was not found."
msgstr "바로가기 `{}` 가 발견되지 않았습니다."
msgstr "`{}` 바로가기가 등록되어 있지 않아요."
#: ../alias.py:316
msgid "There are no aliases on this bot."
msgstr "이 봇에는 바로가기가 없습니다."
msgstr "이 봇에 등록된 별칭이 없어요."
#: ../alias.py:331 ../alias.py:342
msgid "Aliases:"
msgstr "바로가기 리스트:"
msgstr "등록된 별칭 리스트 :"
#: ../alias.py:333 ../alias.py:344
msgid "There are no aliases on this server."
msgstr "이 서버에 별칭이 없습니다."
msgstr "이 서버에 등록된 별칭이 없어요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
@@ -22,15 +22,15 @@ msgstr "Префикс не найден."
#: ../alias.py:198
msgid "You attempted to create a new alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Вы пытались создать новый псевдоним с именем {}, но это имя используется как команда в этом боте."
#: ../alias.py:205
msgid "You attempted to create a new alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Вы пытались создать новый псевдоним с именем {}, но это имя используется как команда на этом сервере."
#: ../alias.py:212
msgid "You attempted to create a new alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Вы пытались создать новый псевдоним с именем {}, но это имя является недопустимым псевдонимом. Имена псевдонимов не могут содержать пробелы."
#: ../alias.py:224
msgid "A new alias with the trigger `{}` has been created."
@@ -38,15 +38,15 @@ msgstr "Был создан новый псевдоним с триггером
#: ../alias.py:236
msgid "You attempted to create a new global alias with the name {} but that name is already a command on this bot."
msgstr ""
msgstr "Вы пытались создать новый глобальный псевдоним с именем {}, но это имя уже используется как команда в этом боте."
#: ../alias.py:243
msgid "You attempted to create a new global alias with the name {} but that alias already exists on this server."
msgstr ""
msgstr "Вы пытались создать новый глобальный псевдоним с именем {}, но это имя уже существует на этом сервере."
#: ../alias.py:250
msgid "You attempted to create a new global alias with the name {} but that name is an invalid alias name. Alias names may not contain spaces."
msgstr ""
msgstr "Вы пытались создать новый псевдоним с именем {], но это имя явлется недопустимым именем для псевдонима. Псевдонимы не могут содержать пробелы."
#: ../alias.py:259
msgid "A new global alias with the trigger `{}` has been created."
@@ -86,5 +86,5 @@ msgstr "Алиасы:"
#: ../alias.py:333 ../alias.py:344
msgid "There are no aliases on this server."
msgstr "На этом сервере еще нет алиасов."
msgstr "На этом сервере нет псевдонимов."

View File

@@ -1,5 +1,56 @@
from pathlib import Path
from aiohttp import ClientSession
import shutil
import asyncio
from .audio import Audio
from .manager import start_lavalink_server
from discord.ext import commands
from redbot.core.data_manager import cog_data_path
LAVALINK_BUILD = 3112
LAVALINK_BUILD_URL = (
"https://ci.fredboat.com/repository/download/"
"Lavalink_Build/{}:id/Lavalink.jar?guest=1"
).format(LAVALINK_BUILD)
LAVALINK_DOWNLOAD_DIR = cog_data_path(raw_name="Audio")
LAVALINK_JAR_FILE = LAVALINK_DOWNLOAD_DIR / "Lavalink.jar"
APP_YML_FILE = LAVALINK_DOWNLOAD_DIR / "application.yml"
BUNDLED_APP_YML_FILE = Path(__file__).parent / "application.yml"
def setup(bot):
bot.add_cog(Audio(bot))
async def download_lavalink(session):
with LAVALINK_JAR_FILE.open(mode='wb') as f:
async with session.get(LAVALINK_BUILD_URL) as resp:
while True:
chunk = await resp.content.read(512)
if not chunk:
break
f.write(chunk)
async def maybe_download_lavalink(loop, cog):
jar_exists = LAVALINK_JAR_FILE.exists()
current_build = await cog.config.current_build()
if not jar_exists or current_build < LAVALINK_BUILD:
LAVALINK_DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
with ClientSession(loop=loop) as session:
await download_lavalink(session)
await cog.config.current_build.set(LAVALINK_BUILD)
shutil.copyfile(str(BUNDLED_APP_YML_FILE), str(APP_YML_FILE))
async def setup(bot: commands.Bot):
cog = Audio(bot)
await maybe_download_lavalink(bot.loop, cog)
await start_lavalink_server(bot.loop)
async def _finish():
await cog.init_config()
bot.add_cog(cog)
bot.loop.create_task(_finish())

View File

@@ -0,0 +1,20 @@
server:
port: 2333 # REST server
lavalink:
server:
password: "youshallnotpass"
ws:
host: "localhost"
port: 2332
sources:
youtube: true
bandcamp: true
soundcloud: true
twitch: true
vimeo: true
mixer: true
http: true
local: false
sentryDsn: ""
bufferDurationMs: 400
youtubePlaylistLoadLimit: 10000

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@@ -18,11 +18,11 @@ msgstr ""
#: ../audio.py:25 ../audio.py:45
msgid "Join a voice channel first!"
msgstr "Du musst zuerst einem Sprach Kanal beitreten!"
msgstr "Tritt zuerst einem Sprachkanal bei!"
#: ../audio.py:33
msgid "Let's play a file that exists pls"
msgstr "Lassen Sie uns eine Datei spielen, die es gibt"
msgstr "Lass uns eine Datei abspielen, die vorhanden ist"
#: ../audio.py:38 ../audio.py:58
msgid "{} is playing a song..."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"
@@ -18,7 +18,7 @@ msgstr ""
#: ../audio.py:25 ../audio.py:45
msgid "Join a voice channel first!"
msgstr ""
msgstr "Aye! Ye need to sail y'ur ship first!"
#: ../audio.py:33
msgid "Let's play a file that exists pls"
@@ -26,17 +26,17 @@ msgstr ""
#: ../audio.py:38 ../audio.py:58
msgid "{} is playing a song..."
msgstr ""
msgstr "{} be dancing to Shanty..."
#: ../audio.py:48
msgid "Youtube links pls"
msgstr ""
msgstr "Aye! A rope to youtube is required!"
#: ../audio.py:67 ../audio.py:77 ../audio.py:87 ../audio.py:97
msgid "I'm not even connected to a voice channel!"
msgstr ""
msgstr "Aye! I never boarded ye ship!"
#: ../audio.py:95
msgid "Volume set."
msgstr ""
msgstr "Aye, shouting voice changed."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -18,25 +18,25 @@ msgstr ""
#: ../audio.py:25 ../audio.py:45
msgid "Join a voice channel first!"
msgstr ""
msgstr "Bergabung dengan channel suara dulu!"
#: ../audio.py:33
msgid "Let's play a file that exists pls"
msgstr ""
msgstr "Tolong memutar file yang ada"
#: ../audio.py:38 ../audio.py:58
msgid "{} is playing a song..."
msgstr ""
msgstr "{} sedang memainkan sebuah lagu..."
#: ../audio.py:48
msgid "Youtube links pls"
msgstr ""
msgstr "Link YouTube"
#: ../audio.py:67 ../audio.py:77 ../audio.py:87 ../audio.py:97
msgid "I'm not even connected to a voice channel!"
msgstr ""
msgstr "Saya belum memasuki channel suara!"
#: ../audio.py:95
msgid "Volume set."
msgstr ""
msgstr "Suara telah di atur."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,25 +18,25 @@ msgstr ""
#: ../audio.py:25 ../audio.py:45
msgid "Join a voice channel first!"
msgstr ""
msgstr "커맨드를 사용하기 전에 음성 채널에 접속해야 해요!"
#: ../audio.py:33
msgid "Let's play a file that exists pls"
msgstr ""
msgstr "파일을 재생해볼게요!"
#: ../audio.py:38 ../audio.py:58
msgid "{} is playing a song..."
msgstr ""
msgstr "{}이(가) 음악을 재생하는 중..."
#: ../audio.py:48
msgid "Youtube links pls"
msgstr ""
msgstr "유튜브 링크를 부탁해요!"
#: ../audio.py:67 ../audio.py:77 ../audio.py:87 ../audio.py:97
msgid "I'm not even connected to a voice channel!"
msgstr ""
msgstr "제가 음성 채널에 접속할 수 없어요!"
#: ../audio.py:95
msgid "Volume set."
msgstr ""
msgstr "음량이 변경됐어요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -0,0 +1,41 @@
import shlex
import asyncio
from subprocess import Popen, DEVNULL
import os
proc = None
SHUTDOWN = asyncio.Event()
async def monitor_lavalink_server(loop):
while not SHUTDOWN.is_set():
if proc.poll() is not None:
break
await asyncio.sleep(0.5)
if not SHUTDOWN.is_set():
print("Lavalink jar shutdown, restarting.")
await start_lavalink_server(loop)
async def start_lavalink_server(loop):
from . import LAVALINK_DOWNLOAD_DIR, LAVALINK_JAR_FILE
start_cmd = "java -jar {}".format(LAVALINK_JAR_FILE.resolve())
global proc
proc = Popen(
shlex.split(start_cmd, posix=os.name == 'posix'),
cwd=str(LAVALINK_DOWNLOAD_DIR),
stdout=DEVNULL, stderr=DEVNULL
)
print("Lavalink jar started. PID: {}".format(proc.pid))
loop.create_task(monitor_lavalink_server(loop))
def shutdown_lavalink_server():
print("Shutting down lavalink server.")
SHUTDOWN.set()
if proc is not None:
proc.terminate()

View File

@@ -1,3 +1,6 @@
import discord
from redbot.core.utils.chat_formatting import box
from redbot.core import checks, bank
from redbot.core.i18n import CogI18n
from discord.ext import commands
@@ -17,6 +20,8 @@ def check_global_setting_guildowner():
if await ctx.bot.is_owner(author):
return True
if not await bank.is_global():
if not isinstance(ctx.channel, discord.abc.GuildChannel):
return False
permissions = ctx.channel.permissions_for(author)
return author == ctx.guild.owner or permissions.administrator
@@ -33,6 +38,8 @@ def check_global_setting_admin():
if await ctx.bot.is_owner(author):
return True
if not await bank.is_global():
if not isinstance(ctx.channel, discord.abc.GuildChannel):
return False
permissions = ctx.channel.permissions_for(author)
is_guild_owner = author == ctx.guild.owner
admin_role = await ctx.bot.db.guild(ctx.guild).admin_role()
@@ -54,20 +61,47 @@ class Bank:
async def bankset(self, ctx: commands.Context):
"""Base command for bank settings"""
if ctx.invoked_subcommand is None:
if await bank.is_global():
bank_name = await bank._conf.bank_name()
currency_name = await bank._conf.currency()
default_balance = await bank._conf.default_balance()
else:
if not ctx.guild:
await ctx.send_help()
return
bank_name = await bank._conf.guild(ctx.guild).bank_name()
currency_name = await bank._conf.guild(ctx.guild).currency()
default_balance = await bank._conf.guild(ctx.guild).default_balance()
settings = (_(
"Bank settings:\n\n"
"Bank name: {}\n"
"Currency: {}\n"
"Default balance: {}"
"").format(bank_name, currency_name, default_balance)
)
await ctx.send(box(settings))
await ctx.send_help()
@bankset.command(name="toggleglobal")
@checks.is_owner()
async def bankset_toggleglobal(self, ctx: commands.Context):
async def bankset_toggleglobal(self, ctx: commands.Context, confirm: bool=False):
"""Toggles whether the bank is global or not
If the bank is global, it will become per-guild
If the bank is per-guild, it will become global"""
cur_setting = await bank.is_global()
await bank.set_global(not cur_setting)
word = _("per-guild") if cur_setting else _("global")
await ctx.send(_("The bank is now {}.").format(word))
if confirm is False:
await ctx.send(
_("This will toggle the bank to be {}, deleting all accounts "
"in the process! If you're sure, type `{}`").format(
word, "{}bankset toggleglobal yes".format(ctx.prefix)
)
)
else:
await bank.set_global(not cur_setting)
await ctx.send(_("The bank is now {}.").format(word))
@bankset.command(name="bankname")
@check_global_setting_guildowner()

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -22,17 +22,17 @@ msgstr "글로벌"
#: ../bank.py:68
msgid "per-guild"
msgstr "길드마다"
msgstr "길드마다"
#: ../bank.py:70
msgid "The bank is now {}."
msgstr "은행 잔고는 `{}`입니다."
msgstr "은행은 이제 {} 이에요."
#: ../bank.py:77
msgid "Bank's name has been set to {}"
msgstr "계좌 이름이 {} 로 설정 되었습니다."
msgstr "은행 이름이 {} 로 설정됐어요."
#: ../bank.py:84
msgid "Currency name has been set to {}"
msgstr "화 이름이 {} 로 설정 되었습니다."
msgstr "화 이름이 {} 로 설정됐어요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -1,15 +1,13 @@
import asyncio
import re
import discord
from discord.ext import commands
from redbot.core import checks
from redbot.core import checks, RedContext
from redbot.core.bot import Red
from redbot.core.i18n import CogI18n
from redbot.core.utils.mod import slow_deletion, mass_purge
from redbot.cogs.mod.log import log
from redbot.core.context import RedContext
_ = CogI18n("Cleanup", __file__)
@@ -20,6 +18,57 @@ class Cleanup:
def __init__(self, bot: Red):
self.bot = bot
@staticmethod
async def check_100_plus(ctx: RedContext, number: int) -> bool:
"""
Called when trying to delete more than 100 messages at once
Prompts the user to choose whether they want to continue or not
"""
def author_check(message):
return message.author == ctx.author
await ctx.send(_('Are you sure you want to delete {} messages? (y/n)').format(number))
response = await ctx.bot.wait_for('message', check=author_check)
if response.content.lower().startswith('y'):
return True
else:
await ctx.send(_('Cancelled.'))
return False
@staticmethod
async def get_messages_for_deletion(
ctx: RedContext, channel: discord.TextChannel, number,
check=lambda x: True, limit=100, before=None, after=None
) -> list:
"""
Gets a list of messages meeting the requirements to be deleted.
Generally, the requirements are:
- We don't have the number of messages to be deleted already
- The message passes a provided check (if no check is provided,
this is automatically true)
- The message is less than 14 days old
"""
to_delete = []
too_old = False
while not too_old and len(to_delete) - 1 < number:
async for message in channel.history(limit=limit,
before=before,
after=after):
if (not number or len(to_delete) - 1 < number) and check(message) \
and (ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
too_old = True
break
elif number and len(to_delete) >= number:
break
before = message
return to_delete
@commands.group()
@checks.mod_or_permissions(manage_messages=True)
async def cleanup(self, ctx: RedContext):
@@ -30,7 +79,7 @@ class Cleanup:
@cleanup.command()
@commands.guild_only()
@commands.bot_has_permissions(manage_messages=True)
async def text(self, ctx: commands.Context, text: str, number: int):
async def text(self, ctx: RedContext, text: str, number: int):
"""Deletes last X messages matching the specified text.
Example:
@@ -42,18 +91,10 @@ class Cleanup:
author = ctx.author
is_bot = self.bot.user.bot
def author_check(message):
return message.author == author
if number > 100:
await ctx.send('Are you sure you want to delete {} messages? (y/n)'.format(number))
response = await self.bot.wait_for('message', check=author_check)
if response.content.startswith('y'):
tmp = await ctx.send('Continuing..')
await tmp.delete()
else:
return await ctx.send('Cancelled.')
cont = await self.check_100_plus(ctx, number)
if not cont:
return
def check(m):
if text in m.content:
@@ -63,25 +104,11 @@ class Cleanup:
else:
return False
to_delete = [ctx.message]
too_old = False
tmp = ctx.message
while not too_old and len(to_delete) - 1 < number:
async for message in channel.history(limit=1000,
before=tmp):
if len(to_delete) - 1 < number and check(message) and\
(ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
too_old = True
break
elif len(to_delete) >= number:
break
tmp = message
to_delete = await self.get_messages_for_deletion(
ctx, channel, number, check=check, limit=1000, before=ctx.message)
reason = "{}({}) deleted {} messages "\
" containing '{}' in channel {}".format(author.name,
" containing '{}' in channel {}.".format(author.name,
author.id, len(to_delete), text, channel.id)
log.info(reason)
@@ -93,7 +120,7 @@ class Cleanup:
@cleanup.command()
@commands.guild_only()
@commands.bot_has_permissions(manage_messages=True)
async def user(self, ctx: commands.Context, user: discord.Member or int, number: int):
async def user(self, ctx: RedContext, user: discord.Member or int, number: int):
"""Deletes last X messages from specified user.
Examples:
@@ -104,18 +131,10 @@ class Cleanup:
author = ctx.author
is_bot = self.bot.user.bot
def author_check(message):
return message.author == author
if number > 100:
await ctx.send('Are you sure you want to delete {} messages? (y/n)'.format(number))
response = await self.bot.wait_for('message', check=author_check)
if response.content.startswith('y'):
tmp = await ctx.send('Continuing..')
await tmp.delete()
else:
return await ctx.send('Cancelled.')
cont = await self.check_100_plus(ctx, number)
if not cont:
return
def check(m):
if isinstance(user, discord.Member) and m.author == user:
@@ -127,24 +146,11 @@ class Cleanup:
else:
return False
to_delete = []
too_old = False
tmp = ctx.message
while not too_old and len(to_delete) - 1 < number:
async for message in channel.history(limit=1000,
before=tmp):
if len(to_delete) - 1 < number and check(message) and\
(ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
too_old = True
break
elif len(to_delete) >= number:
break
tmp = message
to_delete = await self.get_messages_for_deletion(
ctx, channel, number, check=check, limit=1000, before=ctx.message
)
reason = "{}({}) deleted {} messages "\
" made by {}({}) in channel {}"\
" made by {}({}) in channel {}."\
"".format(author.name, author.id, len(to_delete),
user.name, user.id, channel.name)
log.info(reason)
@@ -158,8 +164,8 @@ class Cleanup:
@cleanup.command()
@commands.guild_only()
@commands.bot_has_permissions(manage_messages=True)
async def after(self, ctx: commands.Context, message_id: int):
"""Deletes all messages after specified message
async def after(self, ctx: RedContext, message_id: int):
"""Deletes all messages after specified message.
To get a message id, enable developer mode in Discord's
settings, 'appearance' tab. Then right click a message
@@ -183,15 +189,11 @@ class Cleanup:
await ctx.send(_("Message not found."))
return
to_delete = []
to_delete = await self.get_messages_for_deletion(
ctx, channel, 0, limit=None, after=after
)
async for message in channel.history(after=after):
if (ctx.message.created_at - message.created_at).days < 14:
# Only add messages that are less than
# 14 days old to the deletion queue
to_delete.append(message)
reason = "{}({}) deleted {} messages in channel {}"\
reason = "{}({}) deleted {} messages in channel {}."\
"".format(author.name, author.id,
len(to_delete), channel.name)
log.info(reason)
@@ -201,7 +203,7 @@ class Cleanup:
@cleanup.command()
@commands.guild_only()
@commands.bot_has_permissions(manage_messages=True)
async def messages(self, ctx: commands.Context, number: int):
async def messages(self, ctx: RedContext, number: int):
"""Deletes last X messages.
Example:
@@ -212,36 +214,16 @@ class Cleanup:
is_bot = self.bot.user.bot
def author_check(message):
return message.author == author
if number > 100:
await ctx.send('Are you sure you want to delete {} messages? (y/n)'.format(number))
response = await self.bot.wait_for('message', check=author_check)
cont = await self.check_100_plus(ctx, number)
if not cont:
return
if response.content.startswith('y'):
tmp = await ctx.send('Continuing..')
await tmp.delete()
else:
return await ctx.send('Cancelled.')
else:
tmp = ctx.message
to_delete = await self.get_messages_for_deletion(
ctx, channel, number, limit=1000, before=ctx.message
)
to_delete = []
done = False
while len(to_delete) - 1 < number and not done:
async for message in channel.history(limit=1000, before=tmp):
if len(to_delete) - 1 < number and \
(ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
done = True
break
tmp = message
reason = "{}({}) deleted {} messages in channel {}"\
reason = "{}({}) deleted {} messages in channel {}."\
"".format(author.name, author.id,
number, channel.name)
log.info(reason)
@@ -254,25 +236,17 @@ class Cleanup:
@cleanup.command(name='bot')
@commands.guild_only()
@commands.bot_has_permissions(manage_messages=True)
async def cleanup_bot(self, ctx: commands.Context, number: int):
"""Cleans up command messages and messages from the bot"""
async def cleanup_bot(self, ctx: RedContext, number: int):
"""Cleans up command messages and messages from the bot."""
channel = ctx.message.channel
author = ctx.message.author
is_bot = self.bot.user.bot
def author_check(message):
return message.author == author
if number > 100:
await ctx.send('Are you sure you want to delete {} messages? (y/n)'.format(number))
response = await self.bot.wait_for('message', check=author_check)
if response.content.startswith('y'):
tmp = await ctx.send('Continuing..')
await tmp.delete()
else:
return await ctx.send('Cancelled.')
cont = await self.check_100_plus(ctx, number)
if not cont:
return
prefixes = await self.bot.get_prefix(ctx.message) # This returns all server prefixes
if isinstance(prefixes, str):
@@ -293,24 +267,12 @@ class Cleanup:
return bool(self.bot.get_command(cmd_name))
return False
to_delete = [ctx.message]
too_old = False
tmp = ctx.message
while not too_old and len(to_delete) - 1 < number:
async for message in channel.history(limit=1000, before=tmp):
if len(to_delete) - 1 < number and check(message) and\
(ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
too_old = True
break
elif len(to_delete) >= number:
break
tmp = message
to_delete = await self.get_messages_for_deletion(
ctx, channel, number, check=check, limit=1000, before=ctx.message
)
reason = "{}({}) deleted {} "\
" command messages in channel {}"\
" command messages in channel {}."\
"".format(author.name, author.id, len(to_delete),
channel.name)
log.info(reason)
@@ -321,7 +283,7 @@ class Cleanup:
await slow_deletion(to_delete)
@cleanup.command(name='self')
async def cleanup_self(self, ctx: commands.Context, number: int, match_pattern: str = None):
async def cleanup_self(self, ctx: RedContext, number: int, match_pattern: str = None):
"""Cleans up messages owned by the bot.
By default, all messages are cleaned. If a third argument is specified,
@@ -336,18 +298,10 @@ class Cleanup:
author = ctx.message.author
is_bot = self.bot.user.bot
def author_check(message):
return message.author == author
if number > 100:
await ctx.send('Are you sure you want to delete {} messages? (y/n)'.format(number))
response = await self.bot.wait_for('message', check=author_check)
if response.content.startswith('y'):
tmp = await ctx.send('Continuing..')
await tmp.delete()
else:
return await ctx.send('Cancelled.')
cont = await self.check_100_plus(ctx, number)
if not cont:
return
# You can always delete your own messages, this is needed to purge
can_mass_purge = False
@@ -378,25 +332,13 @@ class Cleanup:
return True
return False
to_delete = []
to_delete = await self.get_messages_for_deletion(
ctx, channel, number, check=check, limit=1000, before=ctx.message
)
# Selfbot convenience, delete trigger message
if author == self.bot.user:
to_delete.append(ctx.message)
number += 1
too_old = False
tmp = ctx.message
while not too_old and len(to_delete) < number:
async for message in channel.history(limit=1000, before=tmp):
if len(to_delete) < number and check(message) and\
(ctx.message.created_at - message.created_at).days < 14:
to_delete.append(message)
elif (ctx.message.created_at - message.created_at).days >= 14:
# Found a message that is 14 or more days old, stop here
too_old = True
break
elif len(to_delete) >= number:
break
tmp = message
if channel.name:
channel_name = 'channel ' + channel.name
@@ -404,7 +346,7 @@ class Cleanup:
channel_name = str(channel)
reason = "{}({}) deleted {} messages "\
"sent by the bot in {}"\
"sent by the bot in {}."\
"".format(author.name, author.id, len(to_delete),
channel_name)
log.info(reason)

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -18,9 +18,9 @@ msgstr ""
#: ../cleanup.py:176
msgid "This command can only be used on bots with bot accounts."
msgstr ""
msgstr "Perintah ini hanya bisa di gunakan kepada bot dengan akun bot."
#: ../cleanup.py:183
msgid "Message not found."
msgstr ""
msgstr "Pesan tidak ditemukan."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,9 +18,9 @@ msgstr ""
#: ../cleanup.py:176
msgid "This command can only be used on bots with bot accounts."
msgstr ""
msgstr "이 커맨드는 봇 계정이 있는 봇만 사용할 수 있어요."
#: ../cleanup.py:183
msgid "Message not found."
msgstr ""
msgstr "메세지를 찾을 수 없어요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"
@@ -22,5 +22,5 @@ msgstr ""
#: ../cleanup.py:183
msgid "Message not found."
msgstr ""
msgstr "Bericht niet gevonden."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -19,49 +19,50 @@ msgstr ""
#: ../customcom.py:44
msgid "Welcome to the interactive random {} maker!\n"
"Every message you send will be added as one of the random response to choose from once this {} is triggered. To exit this interactive menu, type `{}`"
msgstr ""
msgstr "Selamat datang di pembuat interaktif {} acak!\n"
"Setiap pesan yang anda kirim akan ditambahkan sebagai salah satu respon acak untuk dipilih setelah ini {} dipicu. Untuk keluar dari menu interaktif ini, ketik `{}`"
#: ../customcom.py:56
msgid "Add a random response:"
msgstr ""
msgstr "Tambahkan tanggapan acak:"
#: ../customcom.py:119
msgid "Do you want to create a 'randomized' cc? {}"
msgstr ""
msgstr "Apakah Anda ingin membuat cc 'acak'? {}"
#: ../customcom.py:126
msgid "What response do you want?"
msgstr ""
msgstr "Tanggapan apa yang anda inginkan?"
#: ../customcom.py:205 ../customcom.py:235
msgid "Custom command successfully added."
msgstr ""
msgstr "Perintah kustom berhasil ditambahkan."
#: ../customcom.py:207 ../customcom.py:237
msgid "This command already exists. Use `{}` to edit it."
msgstr ""
msgstr "Perintah ini sudah ada. Gunakan '{}' untuk mengeditnya."
#: ../customcom.py:229
msgid "That command is already a standard command."
msgstr ""
msgstr "Perintah ini sudah perintah standar."
#: ../customcom.py:261
msgid "Custom command successfully edited."
msgstr ""
msgstr "Perintah kustom berhasil diubah."
#: ../customcom.py:263
msgid "That command doesn't exist. Use `{}` to add it."
msgstr ""
msgstr "Perintah ini tidak tersedia. Gunakan '{}' untuk menambahkannya."
#: ../customcom.py:282
msgid "Custom command successfully deleted."
msgstr ""
msgstr "Perintah kustom berhasil dihapus."
#: ../customcom.py:284
msgid "That command doesn't exist."
msgstr ""
msgstr "Perintah tersebut tidak ada."
#: ../customcom.py:294
msgid "There are no custom commands in this guild. Use `{}` to start adding some."
msgstr ""
msgstr "Tidak ada perintah kustom dalam server ini. Gunakan '{}' untuk mulai menambahkannya."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -19,49 +19,50 @@ msgstr ""
#: ../customcom.py:44
msgid "Welcome to the interactive random {} maker!\n"
"Every message you send will be added as one of the random response to choose from once this {} is triggered. To exit this interactive menu, type `{}`"
msgstr ""
msgstr "대화형 랜덤 {} 메이커에 오신 것을 환영해요!\n"
"사용자님이 보내는 모든 메시지에 {} 이(가) 트리거 되면 선택할 임의의 대답 중 하나로 추가됍니다. 이 대화형 메뉴를 종료하려면 `{}` 을 입력해야 해요."
#: ../customcom.py:56
msgid "Add a random response:"
msgstr ""
msgstr "등록된 랜덤 대답 리스트 :"
#: ../customcom.py:119
msgid "Do you want to create a 'randomized' cc? {}"
msgstr ""
msgstr "'임의' CC를 생성할까요?"
#: ../customcom.py:126
msgid "What response do you want?"
msgstr ""
msgstr "어떤 대답을 원해요?"
#: ../customcom.py:205 ../customcom.py:235
msgid "Custom command successfully added."
msgstr ""
msgstr "커스텀 커맨드가 성공적으로 추가됐어요."
#: ../customcom.py:207 ../customcom.py:237
msgid "This command already exists. Use `{}` to edit it."
msgstr ""
msgstr "이 커맨드는 이미 추가되어 있어요. 편집하려면 `{}` 을(를) 사용해보세요."
#: ../customcom.py:229
msgid "That command is already a standard command."
msgstr ""
msgstr "해당 커맨드는 봇의 커맨드예요."
#: ../customcom.py:261
msgid "Custom command successfully edited."
msgstr ""
msgstr "커스텀 커맨드가 성공적으로 수정됐어요."
#: ../customcom.py:263
msgid "That command doesn't exist. Use `{}` to add it."
msgstr ""
msgstr "해당 커맨드는 추가되어 있지 않아요. 추가하려면 `{}` 을(를) 사용해보세요."
#: ../customcom.py:282
msgid "Custom command successfully deleted."
msgstr ""
msgstr "커스텀 커맨드가 성공적으로 삭제됐어요."
#: ../customcom.py:284
msgid "That command doesn't exist."
msgstr ""
msgstr "해당 커맨드는 추가되어 있지 않아요."
#: ../customcom.py:294
msgid "There are no custom commands in this guild. Use `{}` to start adding some."
msgstr ""
msgstr "이 길드에 등록된 커스텀 커맨드가 없어요. 추가하려면 `{}` 을(를) 사용해보세요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -0,0 +1,6 @@
from redbot.core.bot import Red
from .dataconverter import DataConverter
def setup(bot: Red):
bot.add_cog(DataConverter(bot))

View File

@@ -0,0 +1,184 @@
from itertools import chain, starmap
from pathlib import Path
from datetime import datetime
from redbot.core.bot import Red
from redbot.core.utils.data_converter import DataConverter as dc
from redbot.core.config import Config
class SpecResolver(object):
"""
Resolves Certain things for DataConverter
"""
def __init__(self, path: Path):
self.v2path = path
self.resolved = set()
self.available_core_conversions = {
'Bank Accounts': {
'cfg': ('Bank', None, 384734293238749),
'file': self.v2path / 'data' / 'economy' / 'bank.json',
'converter': self.bank_accounts_conv_spec
},
'Economy Settings': {
'cfg': ('Economy', 'config', 1256844281),
'file': self.v2path / 'data' / 'economy' / 'settings.json',
'converter': self.economy_conv_spec
},
'Mod Log Cases': {
'cfg': ('ModLog', None, 1354799444),
'file': self.v2path / 'data' / 'mod' / 'modlog.json',
'converter': None # prevents from showing as available
},
'Filter': {
'cfg': ('Filter', 'settings', 4766951341),
'file': self.v2path / 'data' / 'mod' / 'filter.json',
'converter': self.filter_conv_spec
},
'Past Names': {
'cfg': ('Mod', 'settings', 4961522000),
'file': self.v2path / 'data' / 'mod' / 'past_names.json',
'converter': self.past_names_conv_spec
},
'Past Nicknames': {
'cfg': ('Mod', 'settings', 4961522000),
'file': self.v2path / 'data' / 'mod' / 'past_nicknames.json',
'converter': self.past_nicknames_conv_spec
},
'Custom Commands': {
'cfg': ('CustomCommands', 'config', 414589031223512),
'file': self.v2path / 'data' / 'customcom' / 'commands.json',
'converter': self.customcom_conv_spec
}
}
@property
def available(self):
return sorted(
k for k, v in self.available_core_conversions.items()
if v['file'].is_file() and v['converter'] is not None
and k not in self.resolved
)
def unpack(self, parent_key, parent_value):
"""Unpack one level of nesting in a dictionary"""
try:
items = parent_value.items()
except AttributeError:
yield (parent_key, parent_value)
else:
for key, value in items:
yield (parent_key + (key,), value)
def flatten_dict(self, dictionary: dict):
"""Flatten a nested dictionary structure"""
dictionary = {(key,): value for key, value in dictionary.items()}
while True:
dictionary = dict(
chain.from_iterable(
starmap(self.unpack, dictionary.items())
)
)
if not any(
isinstance(value, dict)
for value in dictionary.values()
):
break
return dictionary
def apply_scope(self, scope: str, data: dict):
return {(scope,) + k: v for k, v in data.items()}
def bank_accounts_conv_spec(self, data: dict):
flatscoped = self.apply_scope(Config.MEMBER, self.flatten_dict(data))
ret = {}
for k, v in flatscoped.items():
outerkey, innerkey = tuple(k[:-1]), (k[-1],)
if outerkey not in ret:
ret[outerkey] = {}
if innerkey[0] == 'created_at':
x = int(
datetime.strptime(
v, "%Y-%m-%d %H:%M:%S").timestamp()
)
ret[outerkey].update({innerkey: x})
else:
ret[outerkey].update({innerkey: v})
return ret
def economy_conv_spec(self, data: dict):
flatscoped = self.apply_scope(Config.GUILD, self.flatten_dict(data))
ret = {}
for k, v in flatscoped.items():
outerkey, innerkey = (*k[:-1],), (k[-1],)
if outerkey not in ret:
ret[outerkey] = {}
ret[outerkey].update({innerkey: v})
return ret
def mod_log_cases(self, data: dict):
raise NotImplementedError("This one isn't ready yet")
def filter_conv_spec(self, data: dict):
return {
(Config.GUILD, k): {('filter',): v}
for k, v in data.items()
}
def past_names_conv_spec(self, data: dict):
return {
(Config.USER, k): {('past_names',): v}
for k, v in data.items()
}
def past_nicknames_conv_spec(self, data: dict):
flatscoped = self.apply_scope(Config.MEMBER, self.flatten_dict(data))
ret = {}
for k, v in flatscoped.items():
outerkey, innerkey = (*k[:-1],), (k[-1],)
if outerkey not in ret:
ret[outerkey] = {}
ret[outerkey].update({innerkey: v})
return ret
def customcom_conv_spec(self, data: dict):
flatscoped = self.apply_scope(Config.GUILD, self.flatten_dict(data))
ret = {}
for k, v in flatscoped.items():
outerkey, innerkey = (*k[:-1],), ('commands', k[-1])
if outerkey not in ret:
ret[outerkey] = {}
ccinfo = {
'author': {
'id': 42,
'name': 'Converted from a v2 instance'
},
'command': k[-1],
'created_at': '{:%d/%m/%Y %H:%M:%S}'.format(datetime.utcnow()),
'editors': [],
'response': v
}
ret[outerkey].update({innerkey: ccinfo})
return ret
async def convert(self, bot: Red, prettyname: str):
if prettyname not in self.available:
raise NotImplementedError("No Conversion Specs for this")
info = self.available_core_conversions[prettyname]
filepath, converter = info['file'], info['converter']
(cogname, attr, _id) = info['cfg']
try:
config = getattr(bot.get_cog(cogname), attr)
except (TypeError, AttributeError):
config = Config.get_conf(cogname, _id)
try:
items = converter(dc.json_load(filepath))
await dc(config).dict_import(items)
except Exception:
raise
else:
self.resolved.add(prettyname)

View File

@@ -0,0 +1,82 @@
from pathlib import Path
import asyncio
from discord.ext import commands
from redbot.core import checks, RedContext
from redbot.core.bot import Red
from redbot.core.i18n import CogI18n
from redbot.cogs.dataconverter.core_specs import SpecResolver
from redbot.core.utils.chat_formatting import box
_ = CogI18n('DataConverter', __file__)
class DataConverter:
"""
Cog for importing Red v2 Data
"""
def __init__(self, bot: Red):
self.bot = bot
@checks.is_owner()
@commands.command(name="convertdata")
async def dataconversioncommand(self, ctx: RedContext, v2path: str):
"""
Interactive prompt for importing data from Red v2
Takes the path where the v2 install is
Overwrites values which have entries in both v2 and v3,
use with caution.
"""
resolver = SpecResolver(Path(v2path.strip()))
if not resolver.available:
return await ctx.send(
_("There don't seem to be any data files I know how to "
"handle here. Are you sure you gave me the base "
"installation path?")
)
while resolver.available:
menu = _("Please select a set of data to import by number"
", or 'exit' to exit")
for index, entry in enumerate(resolver.available, 1):
menu += "\n{}. {}".format(index, entry)
menu_message = await ctx.send(box(menu))
def pred(m):
return m.channel == ctx.channel and m.author == ctx.author
try:
message = await self.bot.wait_for(
'message', check=pred, timeout=60
)
except asyncio.TimeoutError:
return await ctx.send(
_('Try this again when you are more ready'))
else:
if message.content.strip().lower() in [
'quit', 'exit', '-1', 'q', 'cancel'
]:
return await ctx.tick()
try:
message = int(message.content.strip())
to_conv = resolver.available[message - 1]
except (ValueError, IndexError):
await ctx.send(
_("That wasn't a valid choice.")
)
continue
else:
async with ctx.typing():
await resolver.convert(self.bot, to_conv)
await ctx.send(_("{} converted.").format(to_conv))
await menu_message.delete()
else:
return await ctx.send(
_("There isn't anything else I know how to convert here."
"\nThere might be more things I can convert in the future.")
)

View File

@@ -0,0 +1,43 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2018-03-12 04:35+EDT\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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: ENCODING\n"
"Generated-By: pygettext.py 1.5\n"
#: ../dataconverter.py:38
msgid "There don't seem to be any data files I know how to handle here. Are you sure you gave me the base installation path?"
msgstr ""
#: ../dataconverter.py:43
msgid "Please select a set of data to import by number, or 'exit' to exit"
msgstr ""
#: ../dataconverter.py:59
msgid "Try this again when you are more ready"
msgstr ""
#: ../dataconverter.py:70
msgid "That wasn't a valid choice."
msgstr ""
#: ../dataconverter.py:76
msgid "{} converted."
msgstr ""
#: ../dataconverter.py:80
msgid ""
"There isn't anything else I know how to convert here.\n"
"There might be more things I can convert in the future."
msgstr ""

View File

@@ -0,0 +1,15 @@
import subprocess
TO_TRANSLATE = [
'../dataconverter.py'
]
def regen_messages():
subprocess.run(
['pygettext', '-n'] + TO_TRANSLATE
)
if __name__ == "__main__":
regen_messages()

View File

@@ -5,6 +5,8 @@ from sys import path as syspath
from typing import Tuple, Union
import discord
import sys
from redbot.core import Config
from redbot.core import checks
from redbot.core.data_manager import cog_data_path
@@ -43,7 +45,7 @@ class Downloader:
self.LIB_PATH.mkdir(parents=True, exist_ok=True)
self.SHAREDLIB_PATH.mkdir(parents=True, exist_ok=True)
if not self.SHAREDLIB_INIT.exists():
with self.SHAREDLIB_INIT.open(mode='w') as _:
with self.SHAREDLIB_INIT.open(mode='w', encoding='utf-8') as _:
pass
if str(self.LIB_PATH) not in syspath:
@@ -192,7 +194,7 @@ class Downloader:
Installs a group of dependencies using pip.
"""
repo = Repo("", "", "", Path.cwd(), loop=ctx.bot.loop)
success = await repo.install_raw_requirements(deps, self.SHAREDLIB_PATH)
success = await repo.install_raw_requirements(deps, self.LIB_PATH)
if success:
await ctx.send(_("Libraries installed."))
@@ -220,7 +222,7 @@ class Downloader:
"""
try:
# noinspection PyTypeChecker
await self._repo_manager.add_repo(
repo = await self._repo_manager.add_repo(
name=name,
url=repo_url,
branch=branch
@@ -232,6 +234,8 @@ class Downloader:
log.exception(_("Something went wrong during the cloning process."))
else:
await ctx.send(_("Repo `{}` successfully added.").format(name))
if repo.install_msg is not None:
await ctx.send(repo.install_msg)
@repo.command(name="delete")
async def _repo_del(self, ctx, repo_name: Repo):
@@ -248,6 +252,7 @@ class Downloader:
Lists all installed repos.
"""
repos = self._repo_manager.get_all_repo_names()
repos = sorted(repos, key=str.lower)
joined = _("Installed Repos:\n") + "\n".join(["+ " + r for r in repos])
for page in pagify(joined, ["\n"], shorten_by=16):
@@ -267,11 +272,18 @@ class Downloader:
"""
Installs a cog from the given repo.
"""
cog = discord.utils.get(repo_name.available_cogs, name=cog_name)
cog = discord.utils.get(repo_name.available_cogs, name=cog_name) # type: Installable
if cog is None:
await ctx.send(_("Error, there is no cog by the name of"
" `{}` in the `{}` repo.").format(cog_name, repo_name.name))
return
elif cog.min_python_version > sys.version_info:
await ctx.send(_(
"This cog requires at least python version {}, aborting install.".format(
'.'.join([str(n) for n in cog.min_python_version])
)
))
return
if not await repo_name.install_requirements(cog, self.LIB_PATH):
await ctx.send(_("Failed to install the required libraries for"
@@ -285,6 +297,8 @@ class Downloader:
await repo_name.install_libraries(self.SHAREDLIB_PATH)
await ctx.send(_("`{}` cog successfully installed.").format(cog_name))
if cog.install_msg is not None:
await ctx.send(cog.install_msg)
@cog.command(name="uninstall")
async def _cog_uninstall(self, ctx, cog_name: InstalledCog):

View File

@@ -38,6 +38,9 @@ class Installable(RepoJSONMixin):
bot_version : `tuple` of `int`
The minimum bot version required for this installation. Right now
this is always :code:`3.0.0`.
min_python_version : `tuple` of `int`
The minimum python version required for this cog. This field will not
apply to repo info.json's.
hidden : `bool`
Whether or not this cog will be hidden from the user when they use
`Downloader`'s commands.
@@ -70,6 +73,7 @@ class Installable(RepoJSONMixin):
self.author = ()
self.bot_version = (3, 0, 0)
self.min_python_version = (3, 5, 1)
self.hidden = False
self.required_cogs = {} # Cog name -> repo URL
self.requirements = ()
@@ -159,9 +163,15 @@ class Installable(RepoJSONMixin):
try:
bot_version = tuple(info.get("bot_version", [3, 0, 0]))
except ValueError:
bot_version = 2
bot_version = self.bot_version
self.bot_version = bot_version
try:
min_python_version = tuple(info.get('min_python_version', [3, 5, 1]))
except ValueError:
min_python_version = self.min_python_version
self.min_python_version = min_python_version
try:
hidden = bool(info.get("hidden", False))
except ValueError:

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,77 +18,77 @@ msgstr ""
#: ../downloader.py:215
msgid "That git repo has already been added under another name."
msgstr "해당 git 저장소는 이미 다른 이름으로 저장 되어 있습니다."
msgstr "해당 git 저장소는 이미 다른 이름으로 저장되어 있어요."
#: ../downloader.py:217 ../downloader.py:218
msgid "Something went wrong during the cloning process."
msgstr "복제 작업중 에러가 발생했습니다."
msgstr "복제하는 과정에서 뭔가 잘못됐어요."
#: ../downloader.py:220
msgid "Repo `{}` successfully added."
msgstr "저장소 `{}` 성공적으로 추가 되었습니다."
msgstr "저장소 `{}` 이(가) 성공적으로 추가됐어요."
#: ../downloader.py:229
msgid "The repo `{}` has been deleted successfully."
msgstr "저장소 `{}` 성공적으로 삭제 되었습니다."
msgstr "저장소 `{}` 이(가) 성공적으로 삭제됐어요."
#: ../downloader.py:237
msgid "Installed Repos:\n"
msgstr "설치된 저장소 리스트:\n"
msgstr "설치된 저장소 리스트 :"
#: ../downloader.py:258
msgid "Error, there is no cog by the name of `{}` in the `{}` repo."
msgstr "에러, `{}` 저장소에 `{}` 로 해당된 cog가 없습니다."
msgstr "에러, `{}` 저장소에 `{}` 로 해당된 cog가 없어요."
#: ../downloader.py:263
msgid "Failed to install the required libraries for `{}`: `{}`"
msgstr "`{}`에 필요한 라이브러리 설치 실패 햇습니다: `{}`"
msgstr "`{}` 에 필요한 라이브러리 설치 실패했어요 : `{}`"
#: ../downloader.py:273
msgid "`{}` cog successfully installed."
msgstr "`{}` cog가 성공적으로 설치 되었습니다."
msgstr "`{}` cog가 성공적으로 설치됐어요."
#: ../downloader.py:289
msgid "`{}` was successfully removed."
msgstr "`{}` 성공적으로 제거되었습니다."
msgstr "`{}` 이(가) 성공적으로 제거됐어요."
#: ../downloader.py:291
msgid "That cog was installed but can no longer be located. You may need to remove it's files manually if it is still usable."
msgstr "해당 cog가 설치되었지만 위치를 찾을수 없습니다. 만약 해당 cog가 사용 가능하다면 유저가 직접 파일지워야 합니다."
msgstr "해당 cog가 설치되었지만 더 이상 찾을 수 없어요. 그래도 사용할 수 있는 경우 수동으로 파일을 제거해야 해요."
#: ../downloader.py:323
msgid "Cog update completed successfully."
msgstr "Cog가 성공적으로 업데이트 되었습니다."
msgstr "Cog가 성공적으로 업데이트됐어요."
#: ../downloader.py:331
msgid "Available Cogs:\n"
msgstr "사용가능한 Cogs:\n"
msgstr "사용 가능한 Cogs :\n"
#: ../downloader.py:343
msgid "There is no cog `{}` in the repo `{}`"
msgstr "저장소 `{}` 에 `{}`로 된 Cog가 없습니다."
msgstr "저장소 `{}` 에 `{}`로 된 Cog가 없어요."
#: ../downloader.py:348
msgid "Information on {}:\n"
"{}"
msgstr "`{}`에 대한 정보:\n"
msgstr "`{}` 에 대한 정보 :\n"
"{}"
#: ../downloader.py:389
msgid "Missing from info.json"
msgstr "Info.json에 정보가 없습니다."
msgstr "Info.json 파일에서 누락됐어요."
#: ../downloader.py:398
msgid "Command: {}\n"
"Made by: {}\n"
"Repo: {}\n"
"Cog name: {}"
msgstr "명령어: {}\n"
"작성자: {}\n"
"저장소: {}\n"
"Cog 이름: {}"
msgstr "커맨드 : {}\n"
"작성자 : {}\n"
"저장소 : {}\n"
"Cog 이름 : {}"
#: ../downloader.py:430
msgid "That command doesn't seem to exist."
msgstr "해당 명령어가 존재하지 않습니다."
msgstr "해당 커맨드가 등록되어 있지 않아요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-19 03:59+UTC\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -13,6 +13,7 @@ from discord.ext import commands
from redbot.core import Config
from redbot.core import data_manager
from redbot.core.utils import safe_delete
from .errors import *
from .installable import Installable, InstallableType
from .json_mixins import RepoJSONMixin
@@ -614,7 +615,7 @@ class RepoManager:
if repo is None:
raise MissingGitRepo("There is no repo with the name {}".format(name))
shutil.rmtree(str(repo.folder_path))
safe_delete(repo.folder_path)
try:
del self._repos[name]

View File

@@ -216,18 +216,9 @@ class Economy:
)
)
else:
if await bank.is_global():
# Bank being global means that the check would cause only
# the owner and any co-owners to be able to run the command
# so if we're in the function, it's safe to assume that the
# author is authorized to use owner-only commands
user = ctx.author
else:
user = ctx.guild.owner
success = await bank.wipe_bank()
if success:
await ctx.send(_("All bank accounts of this guild have been "
"deleted."))
await bank.wipe_bank()
await ctx.send(_("All bank accounts of this guild have been "
"deleted."))
@commands.command()
@guild_only_check()
@@ -244,14 +235,17 @@ class Economy:
await bank.deposit_credits(author, await self.config.PAYDAY_CREDITS())
next_payday = cur_time + await self.config.PAYDAY_TIME()
await self.config.user(author).next_payday.set(next_payday)
await ctx.send(
_("{} Here, take some {}. Enjoy! (+{}"
" {}!)").format(
author.mention, credits_name,
str(await self.config.PAYDAY_CREDITS()),
credits_name
)
)
pos = await bank.get_leaderboard_position(author)
await ctx.send(_(
"{0.mention} Here, take some {1}. Enjoy! (+{2}\n\n"
"You currently have {3} {1}.\n\n"
"You are currently #{4} on the leaderboard!"
).format(
author, credits_name, str(await self.config.PAYDAY_CREDITS()),
str(await bank.get_balance(author)), pos
))
else:
dtime = self.display_time(next_payday - cur_time)
await ctx.send(
@@ -264,12 +258,15 @@ class Economy:
await bank.deposit_credits(author, await self.config.guild(guild).PAYDAY_CREDITS())
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
await self.config.member(author).next_payday.set(next_payday)
await ctx.send(
_("{} Here, take some {}. Enjoy! (+{}"
" {}!)").format(
author.mention, credits_name,
str(await self.config.guild(guild).PAYDAY_CREDITS()),
credits_name))
pos = await bank.get_leaderboard_position(author)
await ctx.send(_(
"{0.mention} Here, take some {1}. Enjoy! (+{2})\n\n"
"You currently have {3} {1}.\n\n"
"You are currently #{4} on the leaderboard!"
).format(
author, credits_name, str(await self.config.PAYDAY_CREDITS()),
str(await bank.get_balance(author)), pos
))
else:
dtime = self.display_time(next_payday - cur_time)
await ctx.send(
@@ -278,7 +275,7 @@ class Economy:
@commands.command()
@guild_only_check()
async def leaderboard(self, ctx: commands.Context, top: int = 10):
async def leaderboard(self, ctx: commands.Context, top: int = 10, show_global: bool=False):
"""Prints out the leaderboard
Defaults to top 10"""
@@ -286,26 +283,23 @@ class Economy:
guild = ctx.guild
if top < 1:
top = 10
if await bank.is_global():
bank_sorted = sorted(await bank.get_global_accounts(),
key=lambda x: x.balance, reverse=True)
else:
bank_sorted = sorted(await bank.get_guild_accounts(guild),
key=lambda x: x.balance, reverse=True)
if await bank.is_global() and show_global: # show_global is only applicable if bank is global
guild = None
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
if len(bank_sorted) < top:
top = len(bank_sorted)
topten = bank_sorted[:top]
highscore = ""
place = 1
for acc in topten:
dname = str(acc.name)
if len(dname) >= 23 - len(str(acc.balance)):
dname = dname[:(23 - len(str(acc.balance))) - 3]
dname += "... "
highscore += str(place).ljust(len(str(top)) + 1)
highscore += dname.ljust(23 - len(str(acc.balance)))
highscore += str(acc.balance) + "\n"
place += 1
for pos, acc in enumerate(bank_sorted, 1):
pos = pos
poswidth = 2
name = acc[1]["name"]
namewidth = 35
balance = acc[1]["balance"]
balwidth = 2
highscore += "{pos: <{poswidth}} {name: <{namewidth}s} {balance: >{balwidth}}\n".format(
pos=pos, poswidth=poswidth, name=name, namewidth=namewidth,
balance=balance, balwidth=balwidth
)
if highscore != "":
for page in pagify(highscore, shorten_by=12):
await ctx.send(box(page, lang="py"))

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -85,7 +85,8 @@ msgstr "{} setel akun {} ke {} {}."
#: ../economy.py:212
msgid "This will delete all bank accounts for {}.\n"
"If you're sure, type `{}bank reset yes`"
msgstr ""
msgstr "Ini akan menghapus semua akunbank untuk {}.\n"
"Jika anda telah yakin, ketik {} reset bank ya`"
#: ../economy.py:229
msgid "All bank accounts of this guild have been deleted."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,31 +18,31 @@ msgstr ""
#: ../economy.py:40
msgid "JACKPOT! 226! Your bid has been multiplied * 2500!"
msgstr ""
msgstr "대박이야! 226! 사용자님의 입찰 가격이 2,500을 넘었어요!"
#: ../economy.py:44
msgid "4LC! +1000!"
msgstr ""
msgstr "포 클로버! + 1000!"
#: ../economy.py:48
msgid "Three cherries! +800!"
msgstr ""
msgstr "체리 셋! +800!"
#: ../economy.py:52
msgid "2 6! Your bid has been multiplied * 4!"
msgstr ""
msgstr "2 6! 사용자님의 입찰 가격이 4배로 늘었어요!"
#: ../economy.py:56
msgid "Two cherries! Your bid has been multiplied * 3!"
msgstr ""
msgstr "체리 두 개! 사용자님의 입찰 가격이 3배로 올랐어요!"
#: ../economy.py:60
msgid "Three symbols! +500!"
msgstr ""
msgstr "3개의 심볼! +500!"
#: ../economy.py:64
msgid "Two consecutive symbols! Your bid has been multiplied * 2!"
msgstr ""
msgstr "2연속 심볼! 당신의 입찰 가격이 2배로 늘었어요!"
#: ../economy.py:68
msgid "Slot machine payouts:\n"
@@ -53,74 +53,86 @@ msgid "Slot machine payouts:\n"
"{cherries.value} {cherries.value} Bet * 3\n\n"
"Three symbols: +500\n"
"Two symbols: Bet * 2"
msgstr ""
msgstr "슬롯 머신 지불금 :\n"
"{two.value} {two.value} {six.value} 베팅 * 2500\n"
"{flc.value} {flc.value} {flc.value} +1000\n"
"{cherries.value} {cherries.value} {cherries.value} +800\n"
"{two.value} {six.value} 베팅 * 4\n"
"{cherries.value} {cherries.value} 베팅 * 3"
#: ../economy.py:157
msgid "{}'s balance is {} {}"
msgstr ""
msgstr "{}의 잔액은 {} {} 이에요."
#: ../economy.py:171
msgid "{} transferred {} {} to {}"
msgstr ""
msgstr "{1} 이(가) {2} {3} {4} 으로 전송됐어요."
#: ../economy.py:191
msgid "{} added {} {} to {}'s account."
msgstr ""
msgstr "{1} 이(가) {4}의 계정에 {2} {3} 을(를) 추가했어요."
#: ../economy.py:196
msgid "{} removed {} {} from {}'s account."
msgstr ""
msgstr "{1} 이(가) {4}의 계정에서 {3} {4} 을(를) 제거했어요."
#: ../economy.py:201
msgid "{} set {}'s account to {} {}."
msgstr ""
msgstr "{1} 이(가) {4}의 계정을 {2} {3} (으)로 설정했어요."
#: ../economy.py:212
msgid "This will delete all bank accounts for {}.\n"
"If you're sure, type `{}bank reset yes`"
msgstr ""
msgstr "{} 에 대한 모든 은행 계정이 삭제될 거예요.\n"
"확실한 경우 `{}bank reset yes` 를 입력해야 해요."
#: ../economy.py:229
msgid "All bank accounts of this guild have been deleted."
msgstr ""
msgstr "이 길드의 모든 은행 계정이 삭제됐어요."
#: ../economy.py:248 ../economy.py:268
msgid "{} Here, take some {}. Enjoy! (+{} {}!)"
msgstr ""
msgstr "{} 여기요, 조금의 {} 을(를) 받아요. 즐겨요! (+{} {}!)"
#: ../economy.py:258 ../economy.py:276
msgid "{} Too soon. For your next payday you have to wait {}."
msgstr ""
msgstr "{} 너무 일러요. 다음 월급날을 위해서 {} 을(를) 기다려야 해요."
#: ../economy.py:313
msgid "There are no accounts in the bank."
msgstr ""
msgstr "은행에 등록된 계좌가 없어요."
#: ../economy.py:339
msgid "You're on cooldown, try again in a bit."
msgstr ""
msgstr "사용자님은 지금 쿨타임이에요. 잠시 후에 다시 시도해보세요."
#: ../economy.py:342
msgid "That's an invalid bid amount, sorry :/"
msgstr ""
msgstr "잘못된 입찰 금액이에요, 죄송해요. ;/"
#: ../economy.py:345
msgid "You ain't got enough money, friend."
msgstr ""
msgstr "동작 그만, 밑장빼기냐? 돈이 없잖아."
#: ../economy.py:391
msgid "{}\n"
"{} {}\n\n"
"Your bid: {}\n"
"{} → {}!"
msgstr ""
msgstr "{}\n"
"{} {}\n\n"
"사용자님의 입찰 금액 : {}\n"
"{} → {}!"
#: ../economy.py:398
msgid "{}\n"
"{} Nothing!\n"
"Your bid: {}\n"
"{} → {}!"
msgstr ""
msgstr "{}\n"
"{} 읎어요!\n"
"사용자님의 입찰 금액 : {}\n"
"{} → {}!"
#: ../economy.py:423
msgid "Minimum slot bid: {}\n"
@@ -129,65 +141,70 @@ msgid "Minimum slot bid: {}\n"
"Payday amount: {}\n"
"Payday cooldown: {}\n"
"Amount given at account registration: {}"
msgstr ""
msgstr "최소 슬롯 입찰 수 : {}\n"
"최대 슬롯 입찰 수 : {}\n"
"슬롯 쿨타임 : {}\n"
"급여 금액 : {}\n"
"급여의 재사용 가능 시간 : {}\n"
"계좌 등록 시 지급된 금액 : {}"
#: ../economy.py:433
msgid "Current Economy settings:"
msgstr ""
msgstr "현재 이코노미 설정 :"
#: ../economy.py:441
msgid "Invalid min bid amount."
msgstr ""
msgstr "최소 입찰 금액이 잘못됐어요."
#: ../economy.py:449
msgid "Minimum bid is now {} {}."
msgstr ""
msgstr "이제 최소 입찰가는 {} {} 이에요."
#: ../economy.py:456
msgid "Invalid slotmax bid amount. Must be greater than slotmin."
msgstr ""
msgstr "슬롯 최대 입찰 금액이 잘못됐어요. 슬롯 최솟값보다 커야 해요."
#: ../economy.py:465
msgid "Maximum bid is now {} {}."
msgstr ""
msgstr "이제 최대 입찰가는 {} {} 이에요."
#: ../economy.py:475
msgid "Cooldown is now {} seconds."
msgstr ""
msgstr "이제 쿨타임은 {} 초예요."
#: ../economy.py:485
msgid "Value modified. At least {} seconds must pass between each payday."
msgstr ""
msgstr "값이 수정됐어요. 각각의 월급날 사이에 적어도 {} 초가 지나야 해요."
#: ../economy.py:494
msgid "Har har so funny."
msgstr ""
msgstr "ㅋㅋㅋ 개 재밌다."
#: ../economy.py:500
msgid "Every payday will now give {} {}."
msgstr ""
msgstr "이제 월급날 때마다 {} {} 을(를) 줄 거예요."
#: ../economy.py:511
msgid "Registering an account will now give {} {}."
msgstr ""
msgstr "이제 계정을 등록하면 {} {} 이(가) 지급돼요."
#: ../economy.py:517
msgid "weeks"
msgstr ""
msgstr ""
#: ../economy.py:518
msgid "days"
msgstr ""
msgstr ""
#: ../economy.py:519
msgid "hours"
msgstr ""
msgstr "시간"
#: ../economy.py:520
msgid "minutes"
msgstr ""
msgstr ""
#: ../economy.py:521
msgid "seconds"
msgstr ""
msgstr ""

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -240,8 +240,8 @@ class Filter:
pass
else:
await modlog.create_case(
server, message.created_at, "filterban",
author, server.me, reason
self.bot, server, message.created_at,
"filterban", author, server.me, reason
)
async def on_message(self, message: discord.Message):

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -18,49 +18,49 @@ msgstr ""
#: ../filter.py:62
msgid "Filtered in this server:"
msgstr ""
msgstr "Disaring pada server ini:"
#: ../filter.py:67
msgid "I can't send direct messages to you."
msgstr ""
msgstr "Saya tidak dapat mengirim pesan langsung kepada Anda."
#: ../filter.py:96
msgid "Words added to filter."
msgstr ""
msgstr "Kata-kata yang ditambahkan untuk disaring."
#: ../filter.py:98
msgid "Words already in the filter."
msgstr ""
msgstr "Kata-kata yang sudah di disaring."
#: ../filter.py:127
msgid "Words removed from filter."
msgstr ""
msgstr "Kata-kata dihapus dari penyaring."
#: ../filter.py:129
msgid "Those words weren't in the filter."
msgstr ""
msgstr "Kata-kata tidak dalam penyaring."
#: ../filter.py:142
msgid "Names and nicknames will no longer be checked against the filter"
msgstr ""
msgstr "Nama dan julukan tidak lagi dapat diperiksa terhadap penyaring"
#: ../filter.py:147
msgid "Names and nicknames will now be checked against the filter"
msgstr ""
msgstr "Nama dan julukan akan di periksa terhadap penyaring"
#: ../filter.py:160
msgid "The name to use on filtered names has been set"
msgstr ""
msgstr "Nama yang digunakan untuk penyaring telah ditetapkan"
#: ../filter.py:171
msgid "Count and timeframe either both need to be 0 or both need to be greater than 0!"
msgstr ""
msgstr "Count dan jangka waktu keduanya harus 0 atau keduanya harus lebih besar dari 0!"
#: ../filter.py:179
msgid "Autoban disabled."
msgstr ""
msgstr "Autoban dimatikan."
#: ../filter.py:183
msgid "Count and time have been set."
msgstr ""
msgstr "Jumlah dan waktu telah ditetapkan."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,49 +18,49 @@ msgstr ""
#: ../filter.py:62
msgid "Filtered in this server:"
msgstr ""
msgstr "이 서버에서 필터링 된 항목 :"
#: ../filter.py:67
msgid "I can't send direct messages to you."
msgstr ""
msgstr "사용자님에게 직접 메시지를 보낼 수 없어요."
#: ../filter.py:96
msgid "Words added to filter."
msgstr ""
msgstr "필터링에 추가된 단어예요."
#: ../filter.py:98
msgid "Words already in the filter."
msgstr ""
msgstr "필터에 이미 있는 단어예요."
#: ../filter.py:127
msgid "Words removed from filter."
msgstr ""
msgstr "필터에서 제거된 단어예요."
#: ../filter.py:129
msgid "Those words weren't in the filter."
msgstr ""
msgstr "해당 단어들은 필터에 들어 있지 않아요."
#: ../filter.py:142
msgid "Names and nicknames will no longer be checked against the filter"
msgstr ""
msgstr "필터에 대한 이름 및 닉네임을 더 이상 확인할 수 없어요."
#: ../filter.py:147
msgid "Names and nicknames will now be checked against the filter"
msgstr ""
msgstr "이제 이름과 닉네임을 필터에서 개별적으로 인식해요."
#: ../filter.py:160
msgid "The name to use on filtered names has been set"
msgstr ""
msgstr "필터링 된 이름에 사용할 이름이 설정됐어요."
#: ../filter.py:171
msgid "Count and timeframe either both need to be 0 or both need to be greater than 0!"
msgstr ""
msgstr "개수와 시간은 모두 0이어야 하거나 0보다 커야 해요!"
#: ../filter.py:179
msgid "Autoban disabled."
msgstr ""
msgstr "자동 밴이 중지됐어요."
#: ../filter.py:183
msgid "Count and time have been set."
msgstr ""
msgstr "개수와 시간이 설정됐어요."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -90,7 +90,7 @@ class General:
msg = ""
if user.id == ctx.bot.user.id:
user = ctx.author
msg = _("Nice try. You think this is funny?"
msg = _("Nice try. You think this is funny?\n"
"How about *this* instead:\n\n")
char = "abcdefghijklmnopqrstuvwxyz"
tran = "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz"
@@ -216,24 +216,24 @@ class General:
created_on = _("{}\n({} days ago)").format(user_created, since_created)
joined_on = _("{}\n({} days ago)").format(user_joined, since_joined)
game = _("Chilling in {} status").format(user.status)
if user.game is None: # Default status
activity = _("Chilling in {} status").format(user.status)
if user.activity is None: # Default status
pass
elif user.game.type == 0: # "Playing" status
game = _("Playing {}").format(user.game.name)
elif user.game.type == 1: # "Streaming" status
game = _("Streaming [{}]({})").format(user.game.name, user.game.url)
elif user.game.type == 2: # "Listening" status
game = _("Listening to {}").format(user.game.name)
elif user.game.type == 3: # "Watching" status
game = _("Watching {}").format(user.game.name)
elif user.activity.type == discord.ActivityType.playing:
activity = _("Playing {}").format(user.activity.name)
elif user.activity.type == discord.ActivityType.streaming:
activity = _("Streaming [{}]({})").format(user.activity.name, user.activity.url)
elif user.activity.type == discord.ActivityType.listening:
activity = _("Listening to {}").format(user.activity.name)
elif user.activity.type == discord.ActivityType.watching:
activity = _("Watching {}").format(user.activity.name)
if roles:
roles = ", ".join([x.name for x in roles])
else:
roles = _("None")
data = discord.Embed(description=game, colour=user.colour)
data = discord.Embed(description=activity, colour=user.colour)
data.add_field(name=_("Joined Discord on"), value=created_on)
data.add_field(name=_("Joined this guild on"), value=joined_on)
data.add_field(name=_("Roles"), value=roles, inline=False)

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-02-27 01:49-0500\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Pirate English\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:34-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@@ -30,11 +30,11 @@ msgstr "Jelas begitu"
#: ../general.py:43
msgid "Most likely"
msgstr "Most likely"
msgstr "Sewajarnya"
#: ../general.py:43
msgid "Outlook good"
msgstr "Melihat keluar bagus"
msgstr "Pandangan bagus"
#: ../general.py:43
msgid "Signs point to yes"
@@ -50,7 +50,7 @@ msgstr "Ya"
#: ../general.py:44
msgid "Yes definitely"
msgstr "Iya tentu saja"
msgstr "Iya - tentu saja"
#: ../general.py:44
msgid "You may rely on it"
@@ -163,15 +163,15 @@ msgstr "Bermain {}"
#: ../general.py:225
msgid "Streaming [{}]({})"
msgstr ""
msgstr "Streaming [{}]({})"
#: ../general.py:227
msgid "Listening to {}"
msgstr ""
msgstr "Mendengarkan {}"
#: ../general.py:229
msgid "Watching {}"
msgstr ""
msgstr "Menonton {}"
#: ../general.py:234
msgid "None"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:26-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Korean\n"
"MIME-Version: 1.0\n"
@@ -18,222 +18,223 @@ msgstr ""
#: ../general.py:42
msgid "As I see it, yes"
msgstr ""
msgstr "내가 보기엔 그렇지!"
#: ../general.py:42
msgid "It is certain"
msgstr ""
msgstr "틀림없어요!"
#: ../general.py:42
msgid "It is decidedly so"
msgstr ""
msgstr "그건 확실히 그렇지!"
#: ../general.py:43
msgid "Most likely"
msgstr ""
msgstr "아마도 그럴걸?"
#: ../general.py:43
msgid "Outlook good"
msgstr ""
msgstr "오늘은 전망이 좋네요."
#: ../general.py:43
msgid "Signs point to yes"
msgstr ""
msgstr "소라고둥이 말씀하셨다! \"그래\""
#: ../general.py:44
msgid "Without a doubt"
msgstr ""
msgstr "틀림없어!"
#: ../general.py:44
msgid "Yes"
msgstr ""
msgstr "그래요!"
#: ../general.py:44
msgid "Yes definitely"
msgstr ""
msgstr "그래요, 물론이죠!"
#: ../general.py:44
msgid "You may rely on it"
msgstr ""
msgstr "그걸 믿어도 좋아요!"
#: ../general.py:45
msgid "Ask again later"
msgstr ""
msgstr "나중에 다시 물어보세요!"
#: ../general.py:45
msgid "Reply hazy, try again"
msgstr ""
msgstr "의미심장하네요, 다시 시도해보세요."
#: ../general.py:46
msgid "Better not tell you now"
msgstr ""
msgstr "지금은 말해주지 않는게 좋겠어요."
#: ../general.py:46
msgid "Cannot predict now"
msgstr ""
msgstr "지금은 예측할 수 없죠."
#: ../general.py:47
msgid "Concentrate and ask again"
msgstr ""
msgstr "집중해서 다시 물어보세요."
#: ../general.py:47
msgid "Don't count on it"
msgstr ""
msgstr "그렇지 않을거예요."
#: ../general.py:47
msgid "My reply is no"
msgstr ""
msgstr "제 대답은 \"아뇨\"예요."
#: ../general.py:48
msgid "My sources say no"
msgstr ""
msgstr "제 진심이 말하길 \"아뇨\""
#: ../general.py:48
msgid "Outlook not so good"
msgstr ""
msgstr "오늘은 전망이 별로 좋지 않네요."
#: ../general.py:48
msgid "Very doubtful"
msgstr ""
msgstr "동작 그만, 밑장빼기냐?"
#: ../general.py:64
msgid "Not enough choices to pick from."
msgstr ""
msgstr "선택의 폭이 좁은걸?"
#: ../general.py:78
msgid "{} :game_die: {} :game_die:"
msgstr ""
msgstr "{} :game_die: {} :game_die:"
#: ../general.py:81
msgid "{} Maybe higher than 1? ;P"
msgstr ""
msgstr "{} 1보다 클수도 있죠? ;P"
#: ../general.py:93
msgid "Nice try. You think this is funny?How about *this* instead:\n\n"
msgstr ""
msgstr "시도는 좋았어요, 재밌을 것 같아요? 대신 *이건* 어때요? :"
#: ../general.py:106
msgid "*flips a coin and... "
msgstr ""
msgstr "*동전을 던지며..."
#: ../general.py:106
msgid "HEADS!*"
msgstr ""
msgstr "앞면!*"
#: ../general.py:106
msgid "TAILS!*"
msgstr ""
msgstr "뒷면!*"
#: ../general.py:130
msgid "{} You win {}!"
msgstr ""
msgstr "{} {} 을(를) 획득했어요!"
#: ../general.py:134
msgid "{} You lose {}!"
msgstr ""
msgstr "{} {} 을(를) 잃었어요!"
#: ../general.py:138
msgid "{} We're square {}!"
msgstr ""
msgstr "{} 우리는 사각형이에요 {}!"
#: ../general.py:151
msgid "That doesn't look like a question."
msgstr ""
msgstr "그건 질문으로 보이지 않아요."
#: ../general.py:159
msgid " Stopwatch started!"
msgstr ""
msgstr "스톱워치가 시작됐어요!"
#: ../general.py:163
msgid " Stopwatch stopped! Time: **"
msgstr ""
msgstr "스톱워치가 멈췄어요! 시간 : **"
#: ../general.py:216 ../general.py:217
msgid "{}\n"
"({} days ago)"
msgstr ""
msgstr "{}\n"
"({} 일 전에)"
#: ../general.py:219
msgid "Chilling in {} status"
msgstr ""
msgstr "{} 상태로 오싹해졌어요."
#: ../general.py:223
msgid "Playing {}"
msgstr ""
msgstr "재생 중 {}"
#: ../general.py:225
msgid "Streaming [{}]({})"
msgstr ""
msgstr "실시간 스트리밍 [{}]({})"
#: ../general.py:227
msgid "Listening to {}"
msgstr ""
msgstr "듣는 중 {}"
#: ../general.py:229
msgid "Watching {}"
msgstr ""
msgstr "보는 중 {}"
#: ../general.py:234
msgid "None"
msgstr ""
msgstr "읎어요."
#: ../general.py:237
msgid "Joined Discord on"
msgstr ""
msgstr "가입된 디스코드 켜짐"
#: ../general.py:238
msgid "Joined this guild on"
msgstr ""
msgstr "이 길드에 가입된"
#: ../general.py:239 ../general.py:286
msgid "Roles"
msgstr ""
msgstr "역할"
#: ../general.py:240
msgid "Member #{} | User ID: {}"
msgstr ""
msgstr "멤버 # {} | 사용자 ID : {}"
#: ../general.py:257 ../general.py:299
msgid "I need the `Embed links` permission to send this."
msgstr ""
msgstr "이걸 보내려면 'Embed links' 권한이 필요해요."
#: ../general.py:272
msgid "Since {}. That's over {} days ago!"
msgstr ""
msgstr "{} 이후, 그건 {} 일 전의 일이에요!"
#: ../general.py:282
msgid "Region"
msgstr ""
msgstr "지역"
#: ../general.py:283
msgid "Users"
msgstr ""
msgstr "사용자"
#: ../general.py:284
msgid "Text Channels"
msgstr ""
msgstr "텍스트 채널"
#: ../general.py:285
msgid "Voice Channels"
msgstr ""
msgstr "음성 채널"
#: ../general.py:287
msgid "Owner"
msgstr ""
msgstr "주인님"
#: ../general.py:288
msgid "Guild ID: "
msgstr ""
msgstr "길드 ID :"
#: ../general.py:343
msgid "Your search terms gave no results."
msgstr ""
msgstr "검색 조건에서 검색 결과가 없어요."
#: ../general.py:345
msgid "There is no definition #{}"
msgstr ""
msgstr "정의 #{} 이(가) 없어요."
#: ../general.py:347
msgid "Error."
msgstr ""
msgstr "에러."

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"

View File

@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: red-discordbot\n"
"POT-Creation-Date: 2018-02-18 14:42+AKST\n"
"PO-Revision-Date: 2018-02-25 21:33-0500\n"
"PO-Revision-Date: 2018-04-02 19:27-0400\n"
"Last-Translator: Kowlin <boxedpp@gmail.com>\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"

View File

@@ -28,7 +28,6 @@ class Image:
self.session.close()
@commands.group(name="imgur")
@commands.guild_only()
async def _imgur(self, ctx):
"""Retrieves pictures from imgur
@@ -40,10 +39,16 @@ class Image:
@_imgur.command(name="search")
async def imgur_search(self, ctx, *, term: str):
"""Searches Imgur for the specified term and returns up to 3 results"""
url = self.imgur_base_url + "time/all/0"
url = self.imgur_base_url + "gallery/search/time/all/0"
params = {"q": term}
headers = {"Authorization": "Client-ID {}".format(await self.settings.imgur_client_id())}
async with self.session.get(url, headers=headers, data=params) as search_get:
imgur_client_id = await self.settings.imgur_client_id()
if not imgur_client_id:
await ctx.send(
_("A client ID has not been set! Please set one with {}").format(
"`{}imgurcreds`".format(ctx.prefix)))
return
headers = {"Authorization": "Client-ID {}".format(imgur_client_id)}
async with self.session.get(url, headers=headers, params=params) as search_get:
data = await search_get.json()
if data["success"]:
@@ -81,9 +86,16 @@ class Image:
elif sort_type == "top":
sort = "top"
imgur_client_id = await self.settings.imgur_client_id()
if not imgur_client_id:
await ctx.send(
_("A client ID has not been set! Please set one with {}").format(
"`{}imgurcreds`".format(ctx.prefix)))
return
links = []
headers = {"Authorization": "Client-ID {}".format(await self.settings.imgur_client_id())}
url = self.imgur_base_url + "r/{}/{}/{}/0".format(subreddit, sort, window)
headers = {"Authorization": "Client-ID {}".format(imgur_client_id)}
url = self.imgur_base_url + "gallery/r/{}/{}/{}/0".format(subreddit, sort, window)
async with self.session.get(url, headers=headers) as sub_get:
data = await sub_get.json()
@@ -111,6 +123,7 @@ class Image:
You can get these by visiting https://api.imgur.com/oauth2/addclient
and filling out the form. Enter a name for the application, select
'Anonymous usage without user authorization' for the auth type,
set the authorization callback url to 'https://localhost'
leave the app website blank, enter a valid email address, and
enter a description. Check the box for the captcha, then click Next.
Your client ID will be on the page that loads"""

Some files were not shown because too many files have changed in this diff Show More