import requests as rq
from urllib.parse import quote_plus as escape
import re
from .. import loader, utils
import asyncio
import logging
logger = logging.getLogger(__name__)
# simplified cuttly api
class CuttlyApi:
def __init__(self, token, api_url='https://cutt.ly/api/api.php'):
self.token = token
self.api_url = api_url
self.error_codes = {
1: 'Link is already shortened',
2: 'Link to short is not a link',
3: 'Short link https://cutt.ly/{name} is taken',
4: 'Invalid API key',
5: 'Link preferred alias contains invalid characters',
6: 'Link is from blocked domain'
}
self.ok_code = 7
def shorten(self, short: str, name: str=None) -> dict:
if not re.fullmatch(r'\w+://.+', short): # add scheme if needed
short = 'http://' + short # assume that it supports http
res = rq.get(self.api_url, params={
"key": self.token,
"short": escape(short, ':/%._-'),
"name": name
})
res = res.json()['url']
return res
@loader.tds
class CuttlyMod(loader.Module):
"""URL shortener module"""
# make errors translatable
strings = {
"name": "Cutt.ly",
"error_1": "Link is already shortened",
"error_2": "It is not a link",
"error_3": "Short link https://cutt.ly/{name} is taken",
"error_4": "Invalid API key. Change it in config.",
"error_5": "Link preferred alias contains invalid characters",
"error_6": "Link is from blocked domain",
"unknown_error": "Unknown error {}. Check https://cutt.ly/cuttly-api for information.",
"ok": "Shorted!\nShort link: {short}\nFull link: {full}",
"ok_nofull": "Shorted!\nShort link: {short}",
"no_args": "At least 1 argument needed - the link you gonna to short",
"many_args": "At most 2 arguments - the link you gonna to short and preferred alias for it."
}
def __init__(self):
self.config = loader.ModuleConfig(
# name - default - description
"cuttly_api_url", "https://cutt.ly/api/api.php", "Cuttly API URL, took from https://cutt.ly/cuttly-api",
"api_key", None, "API key for cutt.ly. Register there and take one.",
"include_full_link", True, "Shall bot include full link into answer."
)
def config_complete(self):
self.name = self.strings['name']
self.cl = CuttlyApi(self.config['api_key'], self.config['cuttly_api_url'])
async def shortcmd(self, message):
'''usage: .short [preferred_alias]'''
args = utils.get_args(message)
if len(args) < 1:
await utils.answer(message, self.strings['no_args'])
return
elif len(args) > 2:
await utils.answer(message, self.strings['many_args'])
return
if len(args) == 1:
args.append(None)
res = self.cl.shorten(*args)
logger.debug(f'Got response from cutt.ly: {res}')
if res['status'] != self.cl.ok_code:
try:
msg = self.strings[f'error_{res["status"]}']
except KeyError: # Unknown error, not in strings yet
msg = self.strings['unknown_error'].format(res['status'])
else:
if self.config['include_full_link']:
msg = self.strings['ok']
else:
msg = self.strings['ok_nofull']
await utils.answer(message, msg.format(
short = res.get('shortLink', None), # If we got an error
full = res.get('fullLink', None),
name = args[1]
))