Alles miku
Erste Anpassungen für Mikudayobot
This commit is contained in:
parent
d3c2e99165
commit
b7ed1dbc80
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
config.lua
|
||||
*.db
|
||||
tg
|
||||
otouto-dev-1.rockspec
|
||||
tmp/*
|
||||
last_commit.txt
|
314
README.md
314
README.md
@ -1,230 +1,109 @@
|
||||
# Brawlbot v2
|
||||
[![Build Status](https://travis-ci.org/Brawl345/Brawlbot-v2.svg?branch=master)](https://travis-ci.org/Brawl345/Brawlbot-v2)
|
||||
|
||||
The plugin-wielding, multipurpose Telegram bot.
|
||||
Der multifunktionale Telegram-Bot.
|
||||
|
||||
[Public Bot](http://telegram.me/mokubot) | [Official Channel](http://telegram.me/otouto) | [Development Group](http://telegram.me/BotDevelopment)
|
||||
[Entwickler auf Telegram](http://telegram.me/Brawl) | [Offizieller Kanal](https://telegram.me/brawlbot_updates)
|
||||
|
||||
otouto is a plugin-based, IRC-style bot written for the [Telegram Bot API](http://core.telegram.org/bots/api). Originally written in February of 2015 as a set of Lua scripts to run on [telegram-cli](http://github.com/vysheng/tg), otouto was open-sourced and migrated to the bot API later in June that year.
|
||||
Brawlbot ist ein auf Plugins basierender Bot, der die [offizielle Telegram Bot API](http://core.telegram.org/bots/api) benutzt. Ursprünglich wurde er im Dezember 2014 auf Basis von Yagops [Telegram Bot](https://github.com/yagop/telegram-bot/) entwickelt, da aber die Entwicklung von tg-cli [zum Stillstand](https://brawlbot.tk/posts/ein-neuanfang) gekommen ist, wurden alle Plugins des bisher proprietären Brawlbots im Juni 2016 auf die Bot-API portiert und open-sourced.
|
||||
**Brawlbot v2 basiert auf [otouto](https://github.com/topkecleon/otouto) von Topkecleon.**
|
||||
|
||||
otouto is free software; you are free to redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3. See **LICENSE** for details.
|
||||
Brawlbot v2 ist freie Software; du darfst in modifizieren und weiterverbreiten, allerdings musst du dich an die GNU Affero General Public License v3 halten, siehe **LICENSE** für Details.
|
||||
|
||||
**The Manual**
|
||||
##Anleitung
|
||||
|
||||
| For Users | For Coders |
|
||||
| Für User | Für Entwickler|
|
||||
|:----------------------------------------------|:------------------------------|
|
||||
| [Setup](#setup) | [Plugins](#plugins) |
|
||||
| [Control plugins](#control-plugins) | [Bindings](#bindings) |
|
||||
| [Group Administration](#group-administration) | [Output style](#output-style) |
|
||||
| [List of plugins](#list-of-plugins) | [Contributors](#contributors) |
|
||||
| [Bot steuern](#bot-steuern) | [Bindings](#bindings) |
|
||||
| | [Datenbank](#datenbank)
|
||||
|
||||
* * *
|
||||
# Für User
|
||||
## Setup
|
||||
You _must_ have Lua (5.2+), luasocket, luasec, multipart-post, and dkjson installed. You should also have lpeg, though it is not required. It is recommended you install these with LuaRocks.
|
||||
### Ubuntu und Debian
|
||||
Ubuntu und Debian liefern Luarocks nur für Lua 5.1 aus. Um Luarocks für Lua 5.2 zu verwenden, folge bitte der [Anleitung auf StackOverflow](http://stackoverflow.com/a/20359102)
|
||||
|
||||
To get started, clone the repository and set the following values in `config.lua`:
|
||||
### Setup
|
||||
Du benötigst **Lua 5.2+**, eine aktive **Redis-Instanz** und die folgenden **LuaRocks-Module**:
|
||||
* luasocket
|
||||
* luasec
|
||||
* multipart-post
|
||||
* dkjson
|
||||
* lpeg
|
||||
* redis-lua
|
||||
* fakeredis
|
||||
* oauth
|
||||
* xml
|
||||
* feedparser
|
||||
* serpent
|
||||
|
||||
- `bot_api_key` as your bot authorization token from the BotFather.
|
||||
- `admin` as your Telegram ID.
|
||||
Klone danach diese Repo. kopiere die `config.lua.example` nach `config.lua` und trage folgendes ein:
|
||||
|
||||
Optionally:
|
||||
- `bot_api_key`: API-Token vom BotFather
|
||||
- `admin`: Deine Telegram-ID
|
||||
|
||||
- `lang` as the two-letter code representing your language.
|
||||
Starte danach den Bot mit `./launch.sh`. Um den Bot anzuhalten, führe erst `/halt` über Telegram aus.
|
||||
|
||||
Some plugins are not enabled by default. If you wish to enable them, add them to the `plugins` array.
|
||||
Beim Start werden einige Werte in die Redis-Datenbank unter `telegram:credentials` und `telegram:enabled_plugins` eingetragen. Mit `/plugins enable` kannst du Plugins aktivieren, es sind nicht alle von Haus aus aktiviert.
|
||||
|
||||
When you are ready to start the bot, run `./launch.sh`. To stop the bot, send "/halt" through Telegram. If you terminate the bot manually, you risk data loss. If you do you not want the bot to restart automatically, run it with `lua main.lua`.
|
||||
|
||||
Note that certain plugins, such as translate.lua and greetings.lua, will require privacy mode to be disabled. Additionally, some plugins may require or make use of various API keys:
|
||||
|
||||
- `bing.lua`: [Bing Search API](http://datamarket.azure.com/dataset/bing/search) key (`bing_api_key`)
|
||||
- `gImages.lua` & `youtube.lua`: Google [API](http://console.developers.google.com) and [CSE](https://cse.google.com/cse) keys (`google_api_key`, `google_cse_key`)
|
||||
- `weather.lua`: [OpenWeatherMap](http://openweathermap.org) API key (`owm_api_key`)
|
||||
- `lastfm.lua`: [last.fm](http://last.fm/api) API key (`lastfm_api_key`)
|
||||
- `bible.lua`: [Biblia](http://api.biblia.com) API key (`biblia_api_key`)
|
||||
- `cats.lua`: [The Cat API](http://thecatapi.com) API key (optional) (`thecatapi_key`)
|
||||
- `apod.lua`: [NASA](http://api.nasa.gov) API key (`nasa_api_key`)
|
||||
- `translate.lua`: [Yandex](http://tech.yandex.com/keys/get) API key (`yandex_key`)
|
||||
- `chatter.lua`: [SimSimi](http://developer.simsimi.com/signUp) API key (`simsimi_key`)
|
||||
Einige Plugins benötigen API-Keys, bitte gehe die einzelnen Plugins durch, bevor du sie aktivierst!
|
||||
|
||||
* * *
|
||||
|
||||
## Control plugins
|
||||
Some plugins are designed to be used by the bot's owner. Here are some examples, how they're used, and what they do.
|
||||
## Bot steuern
|
||||
Ein Administrator kann den Bot über folgende Plugins steuern:
|
||||
|
||||
| Plugin | Command | Function |
|
||||
| Plugin | Kommando | Funktion |
|
||||
|:----------------|:-----------|:---------------------------------------------------|
|
||||
| `control.lua` | /reload | Reloads all plugins and configuration. |
|
||||
| | /halt | Shuts down the bot after saving the database. |
|
||||
| | /script | Runs a list a bot commands, separated by newlines. |
|
||||
| `blacklist.lua` | /blacklist | Blocks people from using the bot. |
|
||||
| `shell.lua` | /run | Executes shell commands on the host system. |
|
||||
| `luarun.lua` | /lua | Executes Lua commands in the bot's environment. |
|
||||
| `banhammer.lua` | Siehe /hilfe banhammer| Blockt User vom Bot und kann Whitelist aktivieren
|
||||
| `control.lua` | /restart | Startet den Bot neu |
|
||||
| | /halt | Speichert die Datenbank und stoppt den Bot |
|
||||
| | /script | Führt mehrere Kommandos aus, getrennt mit Zeilenumbrüchen |
|
||||
| `luarun.lua` | /lua | Führt LUA-Kommandos aus |
|
||||
| `plugins.lua` | /plugins enable/disable | Aktiviert/deaktiviert Plugins |
|
||||
| `shell.lua` | /sh | Führt Shell-Kommandos aus |
|
||||
|
||||
* * *
|
||||
|
||||
## Group Administration
|
||||
The administration plugin enables self-hosted, single-realm group administration, supporting both normal groups and supergroups whch are owned by the bot owner. This works by sending TCP commands to an instance of tg running on the owner's account.
|
||||
|
||||
To get started, run `./tg-install.sh`. Note that this script is written for Ubuntu/Debian. If you're running Arch (the only acceptable alternative), you'll have to do it yourself. If that is the case, note that otouto uses the "test" branch of tg, and the AUR package `telegram-cli-git` will not be sufficient, as it does not have support for supergroups yet.
|
||||
|
||||
Once the installation is finished, enable the `administration` plugin in your config file. **The administration plugin must be loaded before the `about` and `blacklist` plugins.** You may have reason to change the default TCP port (4567); if that is the case, remember to change it in `tg-launch.sh` as well. Run `./tg-launch.sh` in a separate screen/tmux window. You'll have to enter your phone number and go through the login process the first time. The script is set to restart tg after two seconds, so you'll need to Ctrl+C after exiting.
|
||||
|
||||
While tg is running, you may start/reload otouto with `administration.lua` enabled, and have access to a wide variety of administrative commands and automata. The administration "database" is stored in `administration.json`. To start using otouto to administrate a group (note that you must be the owner (or an administrator)), send `/gadd` to that group. For a list of commands, use `/ahelp`. Below I'll describe various functions now available to you.
|
||||
|
||||
| Command | Function | Privilege | Internal? |
|
||||
|:------------|:------------------------------------------------|:----------|:----------|
|
||||
| /groups | Returns a list of administrated groups (except the unlisted). | 1 | N |
|
||||
| /ahelp | Returns a list of accessible administrative commands. | 1 | Y |
|
||||
| /ops | Returns a list of the moderators and governor of a group. | 1 | Y |
|
||||
| /desc | Returns detailed information for a group. | 1 | Y |
|
||||
| /rules | Returns the rules of a group. | 1 | Y |
|
||||
| /motd | Returns the message of the day of a group. | 1 | Y |
|
||||
| /link | Returns the link for a group. | 1 | Y |
|
||||
| /kick | Removes the target from the group. | 2 | Y |
|
||||
| /ban | Bans the target from the group. | 2 | Y |
|
||||
| /unban | Unbans the target from the group. | 2 | Y |
|
||||
| /setmotd | Sets the message of the day for a group. | 2 | Y |
|
||||
| /changerule | Changes an individual group rule. | 3 | Y |
|
||||
| /setrules | Sets the rules for a group. | 3 | Y |
|
||||
| /setlink | Sets the link for a group. | 3 | Y |
|
||||
| /alist | Returns a list of administrators. | 3 | Y |
|
||||
| /flags | Returns a list of flags and their states, or toggles one. | 3 | Y |
|
||||
| /antiflood | Configures antiflood (flag 5) settings. | 3 | Y |
|
||||
| /mod | Promotes a user to a moderator. | 3 | Y |
|
||||
| /demod | Demotes a moderator to a user. | 3 | Y |
|
||||
| /gov | Promotes a user to the governor. | 4 | Y |
|
||||
| /degov | Demotes the governor to a user. | 4 | Y |
|
||||
| /hammer | Blacklists and globally bans a user. | 4 | N |
|
||||
| /unhammer | Unblacklists and globally bans a user. | 4 | N |
|
||||
| /admin | Promotes a user to an administrator. | 5 | N |
|
||||
| /deadmin | Demotes an administrator to a user. | 5 | N |
|
||||
| /gadd | Adds a group to the administrative system. | 5 | N |
|
||||
| /grem | Removes a group from the administrative system. | 5 | Y |
|
||||
| /glist | Returns a list of all administrated groups and their governors. | 5 | N |
|
||||
| /broadcast | Broadcasts a message to all administrated groups. | 5 | N |
|
||||
|
||||
Internal commands can only be run within an administrated group.
|
||||
|
||||
### Description of Privileges
|
||||
|
||||
| # | Title | Description | Scope |
|
||||
|:-:|:--------------|:------------------------------------------------------------------|:-------|
|
||||
| 0 | Banned | Cannot enter the group(s). | Either |
|
||||
| 1 | User | Default rank. | Local |
|
||||
| 2 | Moderator | Can kick/ban/unban users. Can set MOTD. | Local |
|
||||
| 3 | Governor | Can set rules/link, promote/demote moderators, modify flags. | Local |
|
||||
| 4 | Administrator | Can globally ban/unban users, promote/demote governors. | Global |
|
||||
| 5 | Owner | Can add/remove groups, broadcast, promote/demote administrators. | Global |
|
||||
|
||||
Obviously, each greater rank inherits the privileges of the lower, positive ranks.
|
||||
|
||||
### Flags
|
||||
|
||||
| # | Name | Description |
|
||||
|:-:|:------------|:---------------------------------------------------------------------------------|
|
||||
| 1 | unlisted | Removes a group from the /groups listing. |
|
||||
| 2 | antisquig | Automatically removes users for posting Arabic script or RTL characters. |
|
||||
| 3 | antisquig++ | Automatically removes users whose names contain Arabic script or RTL characters. |
|
||||
| 4 | antibot | Prevents bots from being added by non-moderators. |
|
||||
| 5 | antiflood | Prevents flooding by rate-limiting messages per user. |
|
||||
| 6 | antihammer | Allows globally-banned users to enter a group. |
|
||||
|
||||
#### antiflood
|
||||
antiflood (flag 5) provides a system of automatic flood protection by removing users who post too much. It is entirely configurable by a group's governor, an administrator, or the bot owner. For each message to a particular group, a user is awarded a certain number of "points". The number of points is different for each message type. When the user reaches 100 points, he is removed. Points are reset each minute. In this way, if a user posts twenty messages within one minute, he is removed.
|
||||
|
||||
**Default antiflood values:**
|
||||
|
||||
| Type | Points |
|
||||
|:-----|:------:|
|
||||
| text | 5 |
|
||||
| contact | 5 |
|
||||
| audio | 5 |
|
||||
| voice | 5 |
|
||||
| photo | 10 |
|
||||
| document | 10 |
|
||||
| location | 10 |
|
||||
| video | 10 |
|
||||
| sticker | 20 |
|
||||
|
||||
Additionally, antiflood can be configured to automatically ban a user after he has been automatically kicked from a single group a certain number of times in one day. This is configurable as the antiflood value `autoban` and is set to three by default.
|
||||
## Gruppenadministration über tg-cli
|
||||
Dieses Feature wird in Brawlbot nicht unterstützt.
|
||||
|
||||
* * *
|
||||
|
||||
## List of plugins
|
||||
## Liste aller Plugins
|
||||
|
||||
| Plugin | Command | Function | Aliases |
|
||||
|:----------------------|:------------------------------|:--------------------------------------------------------|:--------|
|
||||
| `help.lua` | /help [command] | Returns a list of commands or command-specific help. | /h |
|
||||
| `about.lua` | /about | Returns the about text as configured in config.lua. |
|
||||
| `ping.lua` | /ping | The simplest plugin ever! |
|
||||
| `echo.lua` | /echo ‹text› | Repeats a string of text. |
|
||||
| `bing.lua` | /bing ‹query› | Returns Bing web results. | /g |
|
||||
| `gImages.lua` | /images ‹query› | Returns a Google image result. | /i |
|
||||
| `gMaps.lua` | /location ‹query› | Returns location data from Google Maps. | /loc |
|
||||
| `youtube.lua` | /youtube ‹query› | Returns the top video result from YouTube. | /yt |
|
||||
| `wikipedia.lua` | /wikipedia ‹query› | Returns the summary of a Wikipedia article. | /w |
|
||||
| `lastfm.lua` | /np [username] | Returns the song you are currently listening to. |
|
||||
| `lastfm.lua` | /fmset [username] | Sets your username for /np. /fmset -- will delete it. |
|
||||
| `hackernews.lua` | /hackernews | Returns the latest posts from Hacker News. | /hn |
|
||||
| `imdb.lua` | /imdb ‹query› | Returns film information from IMDb. |
|
||||
| `hearthstone.lua` | /hearthstone ‹query› | Returns data for Hearthstone cards matching the query. | /hs |
|
||||
| `calc.lua` | /calc ‹expression› | Returns conversions and solutions to math expressions. |
|
||||
| `bible.lua` | /bible ‹reference› | Returns a Bible verse. | /b |
|
||||
| `urbandictionary.lua` | /urban ‹query› | Returns the top definition from Urban Dictionary. | /ud |
|
||||
| `time.lua` | /time ‹query› | Returns the time, date, and a timezone for a location. |
|
||||
| `weather.lua` | /weather ‹query› | Returns current weather conditions for a given location. |
|
||||
| `nick.lua` | /nick ‹nickname› | Set your nickname. /nick - will delete it. |
|
||||
| `whoami.lua` | /whoami | Returns user and chat info for you or the replied-to user. | /who |
|
||||
| `eightball.lua` | /8ball | Returns an answer from a magic 8-ball. |
|
||||
| `dice.lua` | /roll ‹nDr› | Returns RNG dice rolls. Uses D&D notation. |
|
||||
| `reddit.lua` | /reddit [r/subreddit ¦ query] | Returns the top results from a subreddit, query, or r/all. | /r |
|
||||
| `xkcd.lua` | /xkcd [query] | Returns an xkcd strip and its alt text. |
|
||||
| `slap.lua` | /slap ‹target› | Gives someone a slap (or worse). |
|
||||
| `commit.lua` | /commit | Returns a commit message from whatthecommit.com. |
|
||||
| `fortune.lua` | /fortune | Returns a UNIX fortune. |
|
||||
| `pun.lua` | /pun | Returns a pun. |
|
||||
| `pokedex.lua` | /pokedex ‹query› | Returns a Pokedex entry. | /dex |
|
||||
| `currency.lua` | /cash [amount] ‹cur› to ‹cur› | Converts one currency to another. |
|
||||
| `cats.lua` | /cat | Returns a cat picture. |
|
||||
| `reactions.lua` | /reactions | Returns a list of emoticons which can be posted by the bot. |
|
||||
| `apod.lua` | /apod [date] | Returns the NASA Astronomy Picture of the Day. |
|
||||
| `dilbert.lua` | /dilbert [date] | Returns a Dilbert strip. |
|
||||
| `patterns.lua` | /s/‹from›/‹to›/ | Search-and-replace using Lua patterns. |
|
||||
| `me.lua` | /me | Returns user-specific data stored by the bot. |
|
||||
| `remind.lua` | /remind <duration> <message> | Reminds a user of something after a duration of minutes. |
|
||||
Brawlbot erhält laufend neue Plugins und wird kontinuierlich weiterentwickelt! Siehe [hier](https://github.com/Brawl345/Brawlbot-v2/tree/master/otouto/plugins) für eine Liste aller Plugins.
|
||||
|
||||
* * *
|
||||
|
||||
#Für Entwickler
|
||||
## Plugins
|
||||
otouto uses a robust plugin system, similar to yagop's [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
||||
Brawlbot benutzt ein Plugin-System, ähnlich Yagops [Telegram-Bot](http://github.com/yagop/telegram-bot).
|
||||
|
||||
Most plugins are intended for public use, but a few are for other purposes, like those for [use by the bot's owner](#control-plugins). See [here](#list-of-plugins) for a list of plugins.
|
||||
Ein Plugin kann fünf Komponenten haben, aber nur zwei werden benötigt:
|
||||
|
||||
A plugin can have five components, and two of them are required:
|
||||
|
||||
| Component | Description | Required? |
|
||||
| Komponente | Beschreibung | Benötigt? |
|
||||
|:------------------|:---------------------------------------------|:----------|
|
||||
| `plugin:action` | Main function. Expects `msg` table as an argument. | Y |
|
||||
| `plugin.triggers` | Table of triggers for the plugin. Uses Lua patterns. | Y |
|
||||
| `plugin:init` | Optional function run when the plugin is loaded. | N |
|
||||
| `plugin:cron` | Optional function to be called every minute. | N |
|
||||
| `plugin.command` | Basic command and syntax. Listed in the help text. | N |
|
||||
| `plugin.doc` | Usage for the plugin. Returned by "/help $command". | N |
|
||||
| `plugin.error` | Plugin-specific error message; false for no message. | N |
|
||||
| `plugin:action` | Hauptfunktion. Benötigt `msg` als Argument, empfohlen wird auch `matches` als drittes Argument nach `config` | J |
|
||||
| `plugin.triggers` | Tabelle von Triggern, (Lua-Patterns), auf die der Bot reagiert | J |
|
||||
| `plugin:init` | Optionale Funkion, die beim Start geladen wird | N |
|
||||
| `plugin:cron` | Wird jede Minute ausgeführt | N |
|
||||
| `plugin.command` | Einfaches Kommando mit Syntax. Wird bei `/hilfe` gelistet | N |
|
||||
| `plugin.doc` | Plugin-Hilfe. Wird mit `/help $kommando` gelistet | N |
|
||||
| `plugin.error` | Plugin-spezifische Fehlermeldung | N |
|
||||
|
||||
The `bot:on_msg_receive` function adds a few variables to the `msg` table for your convenience. These are self-explanatory: `msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
||||
Die`bot:on_msg_receive` Funktion fügt einige nützte Variablen zur ` msg` Tabelle hinzu. Diese sind:`msg.from.id_str`, `msg.to.id_str`, `msg.chat.id_str`, `msg.text_lower`, `msg.from.name`.
|
||||
|
||||
Return values from `plugin:action` are optional, but they do effect the flow. If it returns a table, that table will become `msg`, and `on_msg_receive` will continue with that. If it returns `true`, it will continue with the current `msg`.
|
||||
Rückgabewerte für `plugin:action` sind optional, aber wenn eine Tabelle zurückgegeben wird, wird diese die neue `msg`,-Tabelle und `on_msg_receive` wird damit fortfahren.
|
||||
|
||||
When an action or cron function fails, the exception is caught and passed to the `handle_exception` utilty and is either printed to the console or send to the chat/channel defined in `log_chat` in config.lua.
|
||||
Interaktionen mit der Bot-API sind sehr einfach. Siehe [Bindings](#bindings) für Details.
|
||||
|
||||
Interactions with the bot API are straightforward. See the [Bindings section](#bindings) for details.
|
||||
|
||||
Several functions used in multiple plugins are defined in utilities.lua. Refer to that file for usage and documentation.
|
||||
Einige Funktionen, die oft benötigt werden, sind in `utilites.lua` verfügbar.
|
||||
|
||||
* * *
|
||||
|
||||
## Bindings
|
||||
**Diese Sektion wurde noch nicht lokalisiert.**
|
||||
Calls to the Telegram bot API are performed with the `bindings.lua` file through the multipart-post library. otouto's bindings file supports all standard API methods and all arguments. Its main function, `bindings.request`, accepts four arguments: `self`, `method`, `parameters`, `file`. (At the very least, `self` should be a table containing `BASE_URL`, which is bot's API endpoint, ending with a slash, eg `https://api.telegram.org/bot123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ987654321/`.)
|
||||
|
||||
`method` is the name of the API method. `parameters` (optional) is a table of key/value pairs of the method's parameters to be sent with the method. `file` (super-optional) is a table of a single key/value pair, where the key is the name of the parameter and the value is the filename (if these are included in `parameters` instead, otouto will attempt to send the filename as a file ID).
|
||||
@ -278,53 +157,34 @@ Upon success, bindings will return the deserialized result from the API. Upon fa
|
||||
|
||||
* * *
|
||||
|
||||
## Output style
|
||||
otouto plugins should maintain a consistent visual style in their output. This provides a recognizable and comfortable user experience.
|
||||
## Datenbank
|
||||
Brawlbot benutzt eine interne Datenbank, wie Otouto sie benutzt und Redis. Die "Datenbank" ist eine Tabelle, auf die über die Variable `database` zugegriffen werden kann (normalerweise `self.database`) und die als JSON-encodierte Plaintext-Datei jede Stunde gespeichert wird oder wenn der Bot gestoppt wird (über `/halt`).
|
||||
|
||||
### Titles
|
||||
Title lines should be **bold**, including any names and trailing punctuation (such as colons). The exception to this rule is if the title line includes a query, which should be _italic_. It is also acceptable to have a link somewhere inside a title, usually within parentheses. eg:
|
||||
Das ist die Datenbank-Struktur:
|
||||
|
||||
> **Star Wars: Episode IV - A New Hope (1977)**
|
||||
>
|
||||
> **Search results for** _star wars_**:**
|
||||
>
|
||||
> **Changelog for otouto (**[Github](http://github.com/topkecleon/otouto)**):**
|
||||
```
|
||||
{
|
||||
users = {
|
||||
["55994550"] = {
|
||||
id = 55994550,
|
||||
first_name = "Drew",
|
||||
username = "topkecleon"
|
||||
}
|
||||
},
|
||||
userdata = {
|
||||
["55994550"] = {
|
||||
nickname = "Best coder ever",
|
||||
lastfm = "topkecleon"
|
||||
}
|
||||
},
|
||||
version = "2.1"
|
||||
}
|
||||
```
|
||||
|
||||
### Lists
|
||||
Numerated lists should be done with the number and its following punctuation bolded. Unnumbered lists should use the bullet character ( • ). eg:
|
||||
`database.users` speichert User-Informationen, wie Usernamen, IDs, etc., wenn der Bot den User sieht. Jeder Tabellen-Key ist die User-ID als String.
|
||||
|
||||
> **1.** Life as a quick brown fox.
|
||||
>
|
||||
> **2.** The art of jumping over lazy dogs.
|
||||
`database.userdata` speichert Daten von verschiedenen Plugins, hierzu wird aber für Brawlbot-Plugins Redis verwendet.
|
||||
|
||||
and
|
||||
`database.version` speichert die Bot-Version.
|
||||
|
||||
> • Life as a quick brown fox.
|
||||
>
|
||||
> • The art of jumping over lazy dogs.
|
||||
|
||||
### Links
|
||||
Always name your links. Even then, use them with discretion. Excessive links make a post look messy. Links are reasonable when a user may want to learn more about something, but should be avoided when all desirable information is provided. One appropriate use of linking is to provide a preview of an image, as xkcd.lua and apod.lua do.
|
||||
|
||||
### Other Stuff
|
||||
User IDs should appear within brackets, monospaced (`[123456789]`). Descriptions and information should be in plain text, but "flavor" text should be italic. The standard size for arbitrary lists (such as search results) is eight within a private conversation and four elsewhere. This is a trivial pair of numbers (leftover from the deprecated Google search API), but consistency is noticeable and desirable.
|
||||
|
||||
* * *
|
||||
|
||||
## Contributors
|
||||
Everybody is free to contribute to otouto. If you are interested, you are invited to [fork the repo](http://github.com/topkecleon/otouto/fork) and start making pull requests. If you have an idea and you are not sure how to implement it, open an issue or bring it up in the [Bot Development group](http://telegram.me/BotDevelopment).
|
||||
|
||||
The creator and maintainer of otouto is [topkecleon](http://github.com/topkecleon). He can be contacted via [Telegram](http://telegram.me/topkecleon), [Twitter](http://twitter.com/topkecleon), or [email](mailto:drew@otou.to).
|
||||
|
||||
[List of contributors.](https://github.com/topkecleon/otouto/graphs/contributors)
|
||||
|
||||
There are a a few ways to contribute if you are not a programmer. For one, your feedback is always appreciated. Drop me a line on Telegram or on Twitter. Secondly, we are always looking for new ideas for plugins. Most new plugins start with community input. Feel free to suggest them on Github or in the Bot Dev group. You can also donate Bitcoin to the following address:
|
||||
`1BxegZJ73hPu218UrtiY8druC7LwLr82gS`
|
||||
|
||||
Contributions are appreciated in all forms. Monetary contributions will go toward server costs. Donators will be eternally honored (at their discretion) on this page.
|
||||
|
||||
| Donators (in chronological order) |
|
||||
|:----------------------------------------------|
|
||||
| [n8 c00](http://telegram.me/n8_c00) |
|
||||
| [Alex](http://telegram.me/sandu) |
|
||||
| [Brayden](http://telegram.me/bb010g) |
|
||||
* * *
|
@ -21,6 +21,10 @@ Sende /hilfe, um zu starten
|
||||
-- The symbol that starts a command. Usually noted as '/' in documentation.
|
||||
cmd_pat = '/',
|
||||
|
||||
-- false = only whitelisted users can use inline querys
|
||||
-- NOTE that it doesn't matter, if the chat is whitelisted! The USER must be whitelisted!
|
||||
enable_inline_for_everyone = true,
|
||||
|
||||
errors = { -- Generic error messages used in various plugins.
|
||||
generic = 'An unexpected error occurred.',
|
||||
connection = 'Verbindungsfehler.',
|
||||
|
154
drua-tg.lua
154
drua-tg.lua
@ -1,154 +0,0 @@
|
||||
--[[
|
||||
drua-tg
|
||||
A fork of JuanPotato's lua-tg (https://github.com/juanpotato/lua-tg),
|
||||
modified to work more naturally from an API bot.
|
||||
|
||||
Usage:
|
||||
drua = require('drua-tg')
|
||||
drua.IP = 'localhost'
|
||||
drua.PORT = 4567
|
||||
drua.message(chat_id, text)
|
||||
]]--
|
||||
|
||||
local SOCKET = require('socket')
|
||||
|
||||
local comtab = {
|
||||
add = { 'chat_add_user %s %s', 'channel_invite %s %s' },
|
||||
kick = { 'chat_del_user %s %s', 'channel_kick %s %s' },
|
||||
rename = { 'rename_chat %s "%s"', 'rename_channel %s "%s"' },
|
||||
link = { 'export_chat_link %s', 'export_channel_link %s' },
|
||||
photo_set = { 'chat_set_photo %s %s', 'channel_set_photo %s %s' },
|
||||
photo_get = { [0] = 'load_user_photo %s', 'load_chat_photo %s', 'load_channel_photo %s' },
|
||||
info = { [0] = 'user_info %s', 'chat_info %s', 'channel_info %s' }
|
||||
}
|
||||
|
||||
local format_target = function(target)
|
||||
target = tonumber(target)
|
||||
if target < -1000000000000 then
|
||||
target = 'channel#' .. math.abs(target) - 1000000000000
|
||||
return target, 2
|
||||
elseif target < 0 then
|
||||
target = 'chat#' .. math.abs(target)
|
||||
return target, 1
|
||||
else
|
||||
target = 'user#' .. target
|
||||
return target, 0
|
||||
end
|
||||
end
|
||||
|
||||
local escape = function(text)
|
||||
text = text:gsub('\\', '\\\\')
|
||||
text = text:gsub('\n', '\\n')
|
||||
text = text:gsub('\t', '\\t')
|
||||
text = text:gsub('"', '\\"')
|
||||
return text
|
||||
end
|
||||
|
||||
local drua = {
|
||||
IP = 'localhost',
|
||||
PORT = 4567
|
||||
}
|
||||
|
||||
drua.send = function(command, do_receive)
|
||||
local s = SOCKET.connect(drua.IP, drua.PORT)
|
||||
assert(s, '\nUnable to connect to tg session.')
|
||||
s:send(command..'\n')
|
||||
local output
|
||||
if do_receive then
|
||||
output = string.match(s:receive('*l'), 'ANSWER (%d+)')
|
||||
output = s:receive(tonumber(output)):gsub('\n$', '')
|
||||
end
|
||||
s:close()
|
||||
return output
|
||||
end
|
||||
|
||||
drua.message = function(target, text)
|
||||
target = format_target(target)
|
||||
text = escape(text)
|
||||
local command = 'msg %s "%s"'
|
||||
command = command:format(target, text)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.send_photo = function(target, photo)
|
||||
target = format_target(target)
|
||||
local command = 'send_photo %s %s'
|
||||
command = command:format(target, photo)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.add_user = function(chat, target)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.add[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.kick_user = function(chat, target)
|
||||
-- Get the group info so tg will recognize the target.
|
||||
drua.get_info(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
target = format_target(target)
|
||||
local command = comtab.kick[a]:format(chat, target)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.rename_chat = function(chat, name)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.rename[a]:format(chat, name)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.export_link = function(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.link[a]:format(chat)
|
||||
return drua.send(command, true)
|
||||
end
|
||||
|
||||
drua.get_photo = function(chat)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_get[a]:format(chat)
|
||||
local output = drua.send(command, true)
|
||||
if output:match('FAIL') then
|
||||
return false
|
||||
else
|
||||
return output:match('Saved to (.+)')
|
||||
end
|
||||
end
|
||||
|
||||
drua.set_photo = function(chat, photo)
|
||||
local a
|
||||
chat, a = format_target(chat)
|
||||
local command = comtab.photo_set[a]:format(chat, photo)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.get_info = function(target)
|
||||
local a
|
||||
target, a = format_target(target)
|
||||
local command = comtab.info[a]:format(target)
|
||||
return drua.send(command, true)
|
||||
end
|
||||
|
||||
drua.channel_set_admin = function(chat, user, rank)
|
||||
chat = format_target(chat)
|
||||
user = format_target(user)
|
||||
local command = 'channel_set_admin %s %s %s'
|
||||
command = command:format(chat, user, rank)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
drua.channel_set_about = function(chat, text)
|
||||
chat = format_target(chat)
|
||||
text = escape(text)
|
||||
local command = 'channel_set_about %s "%s"'
|
||||
command = command:format(chat, text)
|
||||
return drua.send(command)
|
||||
end
|
||||
|
||||
return drua
|
@ -2,6 +2,6 @@
|
||||
|
||||
while true; do
|
||||
lua main.lua
|
||||
echo 'otouto has stopped. ^C to exit.'
|
||||
echo 'Miku wurde gestoppt. ^C zum beenden.'
|
||||
sleep 5s
|
||||
done
|
||||
|
2
main.lua
2
main.lua
@ -1,4 +1,4 @@
|
||||
local bot = require('otouto.bot')
|
||||
local bot = require('miku.bot')
|
||||
|
||||
local instance = {}
|
||||
local config = require('config')
|
||||
|
@ -27,14 +27,20 @@ function bindings:request(method, parameters, file)
|
||||
parameters[k] = tostring(v)
|
||||
end
|
||||
if file and next(file) ~= nil then
|
||||
local file_type, file_name = next(file)
|
||||
local file_file = io.open(file_name, 'r')
|
||||
local file_data = {
|
||||
filename = file_name,
|
||||
local file_type, file_name = next(file)
|
||||
if not file_name then return false end
|
||||
if string.match(file_name, '/home/pi/Mikubot-V2/tmp/') then
|
||||
local file_file = io.open(file_name, 'r')
|
||||
local file_data = {
|
||||
filename = file_name,
|
||||
data = file_file:read('*a')
|
||||
}
|
||||
file_file:close()
|
||||
parameters[file_type] = file_data
|
||||
}
|
||||
file_file:close()
|
||||
parameters[file_type] = file_data
|
||||
else
|
||||
local file_type, file_name = next(file)
|
||||
parameters[file_type] = file_name
|
||||
end
|
||||
end
|
||||
if next(parameters) == nil then
|
||||
parameters = {''}
|
378
miku/bot.lua
Normal file
378
miku/bot.lua
Normal file
@ -0,0 +1,378 @@
|
||||
local bot = {}
|
||||
|
||||
-- Requires are moved to init to allow for reloads.
|
||||
local bindings -- Load Telegram bindings.
|
||||
local utilities -- Load miscellaneous and cross-plugin functions.
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
bot.version = '2.1'
|
||||
|
||||
function bot:init(config) -- The function run when the bot is started or reloaded.
|
||||
|
||||
bindings = require('miku.bindings')
|
||||
utilities = require('miku.utilities')
|
||||
redis = (loadfile "./miku/redis.lua")()
|
||||
cred_data = load_cred()
|
||||
|
||||
assert(
|
||||
config.bot_api_key and config.bot_api_key ~= '',
|
||||
'You did not set your bot token in the config!'
|
||||
)
|
||||
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
|
||||
|
||||
-- Fetch bot information. Try until it succeeds.
|
||||
repeat
|
||||
print('Fetching bot information...')
|
||||
self.info = bindings.getMe(self)
|
||||
until self.info
|
||||
self.info = self.info.result
|
||||
|
||||
-- Load the "database"! ;)
|
||||
if not self.database then
|
||||
self.database = utilities.load_data(self.info.username..'.db')
|
||||
end
|
||||
|
||||
-- MIGRATION CODE 2.0 -> 2.1
|
||||
if self.database.users and self.database.version ~= '2.1' then
|
||||
self.database.userdata = {}
|
||||
for id, user in pairs(self.database.users) do
|
||||
self.database.userdata[id] = {}
|
||||
self.database.userdata[id].nickname = user.nickname
|
||||
self.database.userdata[id].lastfm = user.lastfm
|
||||
user.nickname = nil
|
||||
user.lastfm = nil
|
||||
user.id_str = nil
|
||||
user.name = nil
|
||||
end
|
||||
end
|
||||
-- END MIGRATION CODE
|
||||
|
||||
-- Table to cache user info (usernames, IDs, etc).
|
||||
self.database.users = self.database.users or {}
|
||||
-- Table to store userdata (nicknames, lastfm usernames, etc).
|
||||
self.database.userdata = self.database.userdata or {}
|
||||
-- Save the bot's version in the database to make migration simpler.
|
||||
self.database.version = bot.version
|
||||
-- Add updated bot info to the user info cache.
|
||||
self.database.users = self.database.users or {} -- Table to cache userdata.
|
||||
self.database.users[tostring(self.info.id)] = self.info
|
||||
|
||||
self.plugins = {} -- Load plugins.
|
||||
enabled_plugins = load_plugins()
|
||||
for k,v in pairs(enabled_plugins) do
|
||||
local p = require('miku.plugins.'..v)
|
||||
-- print('loading plugin',v)
|
||||
table.insert(self.plugins, p)
|
||||
self.plugins[k].name = v
|
||||
if p.init then p.init(self, config) end
|
||||
end
|
||||
|
||||
print('Bot wurde erfolgreich gestartet!\n@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
|
||||
|
||||
self.last_update = self.last_update or 0 -- Set loop variables: Update offset,
|
||||
self.last_cron = self.last_cron or os.date('%M') -- the time of the last cron job,
|
||||
self.last_database_save = self.last_database_save or os.date('%H') -- the time of the last database save,
|
||||
self.is_started = true -- and whether or not the bot should be running.
|
||||
|
||||
end
|
||||
|
||||
function bot:on_msg_receive(msg, config) -- The fn run whenever a message is received.
|
||||
-- remove comment to enable debugging
|
||||
-- vardump(msg)
|
||||
-- Cache user info for those involved.
|
||||
|
||||
if msg.date < os.time() - 5 then return end -- Do not process old messages.
|
||||
|
||||
-- Cache user info for those involved.
|
||||
self.database.users[tostring(msg.from.id)] = msg.from
|
||||
if msg.reply_to_message then
|
||||
self.database.users[tostring(msg.reply_to_message.from.id)] = msg.reply_to_message.from
|
||||
elseif msg.forward_from then
|
||||
self.database.users[tostring(msg.forward_from.id)] = msg.forward_from
|
||||
elseif msg.new_chat_member then
|
||||
self.database.users[tostring(msg.new_chat_member.id)] = msg.new_chat_member
|
||||
elseif msg.left_chat_member then
|
||||
self.database.users[tostring(msg.left_chat_member.id)] = msg.left_chat_member
|
||||
end
|
||||
|
||||
msg = utilities.enrich_message(msg)
|
||||
|
||||
-- Support deep linking.
|
||||
if msg.text:match('^'..config.cmd_pat..'start .+') then
|
||||
msg.text = config.cmd_pat .. utilities.input(msg.text)
|
||||
msg.text_lower = msg.text:lower()
|
||||
end
|
||||
|
||||
-- gsub out user name if multiple bots are in the same group
|
||||
if msg.text:match(config.cmd_pat..'([A-Za-z0-9-_-]+)@'..self.info.username) then
|
||||
msg.text = string.gsub(msg.text, config.cmd_pat..'([A-Za-z0-9-_-]+)@'..self.info.username, "/%1")
|
||||
msg.text_lower = msg.text:lower()
|
||||
end
|
||||
|
||||
msg = pre_process_msg(self, msg, config)
|
||||
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
match_plugins(self, msg, config, plugin)
|
||||
end
|
||||
end
|
||||
|
||||
function bot:on_callback_receive(callback, msg, config) -- whenever a new callback is received
|
||||
-- remove comments to enable debugging
|
||||
-- vardump(msg)
|
||||
-- vardump(callback)
|
||||
|
||||
if msg.date < os.time() - 1800 then -- Do not process old messages.
|
||||
utilities.answer_callback_query(self, callback, 'Nachricht älter als eine halbe Stunde, bitte sende den Befehl selbst noch einmal.', true)
|
||||
return
|
||||
end
|
||||
|
||||
if not callback.data:find(':') or not callback.data:find('@'..self.info.username..' ') then
|
||||
return
|
||||
end
|
||||
callback.data = string.gsub(callback.data, '@'..self.info.username..' ', "")
|
||||
local called_plugin = callback.data:match('(.*):.*')
|
||||
local param = callback.data:sub(callback.data:find(':')+1)
|
||||
|
||||
print('Callback Query "'..param..'" für Plugin "'..called_plugin..'" ausgelöst von '..callback.from.first_name..' ('..callback.from.id..')')
|
||||
|
||||
msg = utilities.enrich_message(msg)
|
||||
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
if plugin.name == called_plugin then
|
||||
if is_plugin_disabled_on_chat(plugin.name, msg) then return end
|
||||
plugin:callback(callback, msg, self, config, param)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- NOTE: To enable InlineQuerys, send /setinline to @BotFather
|
||||
function bot:process_inline_query(inline_query, config) -- When an inline query is received
|
||||
-- remove comment to enable debugging
|
||||
-- vardump(inline_query)
|
||||
|
||||
if not config.enable_inline_for_everyone then
|
||||
local is_whitelisted = redis:get('whitelist:user#id'..inline_query.from.id)
|
||||
if not is_whitelisted then return end
|
||||
end
|
||||
|
||||
if inline_query.query == '' then return end
|
||||
if inline_query.query:match('"') then
|
||||
inline_query.query = inline_query.query:gsub('"', '\\"')
|
||||
end
|
||||
|
||||
for _, plugin in ipairs(self.plugins) do
|
||||
match_inline_plugins(self, inline_query, config, plugin)
|
||||
end
|
||||
end
|
||||
|
||||
function bot:run(config)
|
||||
bot.init(self, config) -- Actually start the script.
|
||||
|
||||
while self.is_started do -- Start a loop while the bot should be running.
|
||||
|
||||
local res = bindings.getUpdates(self, { timeout=20, offset = self.last_update+1 } )
|
||||
if res then
|
||||
for _,v in ipairs(res.result) do -- Go through every new message.
|
||||
self.last_update = v.update_id
|
||||
if v.inline_query then
|
||||
bot.process_inline_query(self, v.inline_query, config)
|
||||
elseif v.callback_query then
|
||||
bot.on_callback_receive(self, v.callback_query, v.callback_query.message, config)
|
||||
elseif v.message then
|
||||
bot.on_msg_receive(self, v.message, config)
|
||||
end
|
||||
end
|
||||
else
|
||||
print('Connection error while fetching updates.')
|
||||
end
|
||||
|
||||
if self.last_cron ~= os.date('%M') then -- Run cron jobs every minute.
|
||||
self.last_cron = os.date('%M')
|
||||
utilities.save_data(self.info.username..'.db', self.database) -- Save the database.
|
||||
for i,v in ipairs(self.plugins) do
|
||||
if v.cron then -- Call each plugin's cron function, if it has one.
|
||||
local result, err = pcall(function() v.cron(self, config) end)
|
||||
if not result then
|
||||
utilities.handle_exception(self, err, 'CRON: ' .. i, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.last_database_save ~= os.date('%H') then
|
||||
utilities.save_data(self.info.username..'.db', self.database) -- Save the database.
|
||||
self.last_database_save = os.date('%H')
|
||||
end
|
||||
end
|
||||
|
||||
-- Save the database before exiting.
|
||||
utilities.save_data(self.info.username..'.db', self.database)
|
||||
print('Halted.')
|
||||
end
|
||||
|
||||
-- Apply plugin.pre_process function
|
||||
function pre_process_msg(self, msg, config)
|
||||
for _,plugin in ipairs(self.plugins) do
|
||||
if plugin.pre_process and msg then
|
||||
-- print('Preprocess '..plugin.name) -- remove comment to restore old behaviour
|
||||
new_msg = plugin:pre_process(msg, self, config)
|
||||
end
|
||||
end
|
||||
return new_msg
|
||||
end
|
||||
|
||||
function match_inline_plugins(self, inline_query, config, plugin)
|
||||
for _, trigger in pairs(plugin.inline_triggers or {}) do
|
||||
if string.match(string.lower(inline_query.query), trigger) then
|
||||
local success, result = pcall(function()
|
||||
for k, pattern in pairs(plugin.inline_triggers) do
|
||||
matches = match_pattern(pattern, inline_query.query)
|
||||
if matches then
|
||||
break;
|
||||
end
|
||||
end
|
||||
print('Inline: '..plugin.name..' triggered')
|
||||
return plugin.inline_callback(self, inline_query, config, matches)
|
||||
end)
|
||||
if not success then
|
||||
print(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function match_plugins(self, msg, config, plugin)
|
||||
for _, trigger in pairs(plugin.triggers or {}) do
|
||||
if string.match(msg.text_lower, trigger) then
|
||||
-- Check if Plugin is disabled
|
||||
if is_plugin_disabled_on_chat(plugin.name, msg) then return end
|
||||
local success, result = pcall(function()
|
||||
-- trying to port matches to miku
|
||||
for k, pattern in pairs(plugin.triggers) do
|
||||
matches = match_pattern(pattern, msg.text)
|
||||
if matches then
|
||||
break;
|
||||
end
|
||||
end
|
||||
print(plugin.name..' triggered')
|
||||
return plugin.action(self, msg, config, matches)
|
||||
end)
|
||||
if not success then
|
||||
-- If the plugin has an error message, send it. If it does
|
||||
-- not, use the generic one specified in config. If it's set
|
||||
-- to false, do nothing.
|
||||
if plugin.error then
|
||||
utilities.send_reply(self, msg, plugin.error)
|
||||
elseif plugin.error == nil then
|
||||
utilities.send_reply(self, msg, config.errors.generic, true)
|
||||
end
|
||||
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
|
||||
return
|
||||
end
|
||||
-- If the action returns a table, make that table the new msg.
|
||||
if type(result) == 'table' then
|
||||
msg = result
|
||||
-- If the action returns true, continue.
|
||||
elseif result ~= true then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function is_plugin_disabled_on_chat(plugin_name, msg)
|
||||
local hash = get_redis_hash(msg, 'disabled_plugins')
|
||||
local disabled = redis:hget(hash, plugin_name)
|
||||
|
||||
-- Plugin is disabled
|
||||
if disabled == 'true' then
|
||||
print('Plugin '..plugin_name..' ist in diesem Chat deaktiviert')
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function load_plugins()
|
||||
enabled_plugins = redis:smembers('telegram:enabled_plugins')
|
||||
if not enabled_plugins[1] then
|
||||
create_plugin_set()
|
||||
end
|
||||
return enabled_plugins
|
||||
end
|
||||
|
||||
-- create plugin set if it doesn't exist
|
||||
function create_plugin_set()
|
||||
enabled_plugins = {
|
||||
'control',
|
||||
'about',
|
||||
'id',
|
||||
'echo',
|
||||
'banhammer',
|
||||
'channels',
|
||||
'plugins',
|
||||
'help',
|
||||
'greetings'
|
||||
}
|
||||
print ('Aktiviere Plugins und speicher in telegram:enabled_plugins')
|
||||
for _,plugin in pairs(enabled_plugins) do
|
||||
redis:sadd("telegram:enabled_plugins", plugin)
|
||||
end
|
||||
end
|
||||
|
||||
function load_cred()
|
||||
if redis:exists("telegram:credentials") == false then
|
||||
-- If credentials hash doesnt exists
|
||||
print ("Neuer Credentials-Hash in telegram:credentials erstellt.")
|
||||
create_cred()
|
||||
end
|
||||
return redis:hgetall("telegram:credentials")
|
||||
end
|
||||
|
||||
-- create credentials hash with redis
|
||||
function create_cred()
|
||||
cred = {
|
||||
bitly_access_token = "",
|
||||
cloudinary_apikey = "",
|
||||
cloudinary_api_secret = "",
|
||||
cloudinary_public_id = "",
|
||||
derpibooru_apikey = "",
|
||||
fb_access_token = "",
|
||||
flickr_apikey = "",
|
||||
forecastio_apikey = "",
|
||||
ftp_site = "",
|
||||
ftp_username = "",
|
||||
ftp_password = "",
|
||||
gender_apikey = "",
|
||||
golem_apikey = "",
|
||||
google_apikey = "",
|
||||
google_cse_id = "",
|
||||
gitlab_private_token = "",
|
||||
gitlab_project_id = "",
|
||||
instagram_access_token = "",
|
||||
lyricsnmusic_apikey = "",
|
||||
mal_username = "",
|
||||
mal_pw = "",
|
||||
neutrino_userid = "",
|
||||
neutrino_apikey = "",
|
||||
owm_apikey = "",
|
||||
page2images_restkey = "",
|
||||
plex_token = "",
|
||||
sankaku_username = "",
|
||||
sankaku_pw = "",
|
||||
soundcloud_client_id = "",
|
||||
tumblr_api_key = "",
|
||||
tw_consumer_key = "",
|
||||
tw_consumer_secret = "",
|
||||
tw_access_token = "",
|
||||
tw_access_token_secret = "",
|
||||
x_mashape_key = "",
|
||||
yandex_translate_apikey = "",
|
||||
yandex_rich_content_apikey = "",
|
||||
yourls_site_url = "",
|
||||
yourls_signature_token = ""
|
||||
}
|
||||
redis:hmset("telegram:credentials", cred)
|
||||
print ('Credentials gespeichert in telegram:credentials')
|
||||
end
|
||||
|
||||
return bot
|
@ -3,8 +3,8 @@ local ninegag = {}
|
||||
local HTTP = require('socket.http')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
ninegag.command = '9gag'
|
||||
|
||||
@ -22,19 +22,20 @@ function ninegag:get_9GAG()
|
||||
-- random max json table size
|
||||
local i = math.random(#gag) local link_image = gag[i].src
|
||||
local title = gag[i].title
|
||||
local post_url = gag[i].url
|
||||
return link_image, title, post_url
|
||||
end
|
||||
|
||||
function ninegag:action(msg, config)
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local url, title = ninegag:get_9GAG()
|
||||
local url, title, post_url = ninegag:get_9GAG()
|
||||
if not url then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local file = download_to_file(url)
|
||||
utilities.send_photo(self, msg.chat.id, file, title)
|
||||
utilities.send_photo(self, msg.chat.id, file, title, msg.message_id, '{"inline_keyboard":[[{"text":"Post aufrufen","url":"'..post_url..'"}]]}')
|
||||
end
|
||||
|
||||
return ninegag
|
38
miku/plugins/about.lua
Normal file
38
miku/plugins/about.lua
Normal file
@ -0,0 +1,38 @@
|
||||
local about = {}
|
||||
|
||||
local bot = require('miku.bot')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
about.command = 'about'
|
||||
about.doc = '`Sendet Informationen über den Bot.`'
|
||||
|
||||
about.triggers = {
|
||||
'/about',
|
||||
'/start'
|
||||
}
|
||||
|
||||
function about:action(msg, config)
|
||||
|
||||
-- Filthy hack, but here is where we'll stop forwarded messages from hitting
|
||||
-- other plugins.
|
||||
-- disabled to restore old behaviour
|
||||
-- if msg.forward_from then return end
|
||||
|
||||
local output = config.about_text .. '\nBrawlbot v'..bot.version..', basierend auf miku von topkecleon.'
|
||||
|
||||
if
|
||||
(msg.new_chat_member and msg.new_chat_member.id == self.info.id)
|
||||
or msg.text_lower:match('^'..config.cmd_pat..'about$')
|
||||
or msg.text_lower:match('^'..config.cmd_pat..'about@'..self.info.username:lower()..'$')
|
||||
or msg.text_lower:match('^'..config.cmd_pat..'start$')
|
||||
or msg.text_lower:match('^'..config.cmd_pat..'start@'..self.info.username:lower()..'$')
|
||||
then
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
return
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
return about
|
@ -1,8 +1,8 @@
|
||||
local adfly = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
local HTTPS = require('ssl.https')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function adfly:init(config)
|
||||
adfly.triggers = {
|
123
miku/plugins/afk.lua
Normal file
123
miku/plugins/afk.lua
Normal file
@ -0,0 +1,123 @@
|
||||
-- original plugin by Akamaru [https://ponywave.de]
|
||||
-- I added Redis and automatic online switching back in 2015
|
||||
|
||||
local afk = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function afk:init(config)
|
||||
afk.triggers = {
|
||||
"^/([A|a][F|f][K|k])$",
|
||||
"^/([A|a][F|f][K|k]) (.*)$"
|
||||
}
|
||||
afk.doc = [[*
|
||||
]]..config.cmd_pat..[[afk* _[Text]_: Setzt Status auf AFK mit optionalem Text]]
|
||||
end
|
||||
|
||||
afk.command = 'afk [Text]'
|
||||
|
||||
function afk:is_offline(hash)
|
||||
local afk = redis:hget(hash, 'afk')
|
||||
if afk == "true" then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function afk:get_afk_text(hash)
|
||||
local afk_text = redis:hget(hash, 'afk_text')
|
||||
if afk_text ~= nil and afk_text ~= "" and afk_text ~= "false" then
|
||||
return afk_text
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function afk:switch_afk(user_name, user_id, chat_id, timestamp, text)
|
||||
local hash = 'afk:'..chat_id..':'..user_id
|
||||
|
||||
if afk:is_offline(hash) then
|
||||
local afk_text = afk:get_afk_text(hash)
|
||||
if afk_text then
|
||||
return 'Du bist bereits AFK ('..afk_text..')!'
|
||||
else
|
||||
return 'Du bist bereits AFK!'
|
||||
end
|
||||
end
|
||||
|
||||
print('Setting redis hash afk in '..hash..' to true')
|
||||
redis:hset(hash, 'afk', true)
|
||||
print('Setting redis hash timestamp in '..hash..' to '..timestamp)
|
||||
redis:hset(hash, 'time', timestamp)
|
||||
|
||||
if text then
|
||||
print('Setting redis hash afk_text in '..hash..' to '..text)
|
||||
redis:hset(hash, 'afk_text', text)
|
||||
return user_name..' ist AFK ('..text..')'
|
||||
else
|
||||
return user_name..' ist AFK'
|
||||
end
|
||||
end
|
||||
|
||||
function afk:pre_process(msg, self)
|
||||
if msg.chat.type == "private" then
|
||||
-- Ignore
|
||||
return
|
||||
end
|
||||
|
||||
local user_name = get_name(msg)
|
||||
local user_id = msg.from.id
|
||||
local chat_id = msg.chat.id
|
||||
local hash = 'afk:'..chat_id..':'..user_id
|
||||
|
||||
|
||||
if afk:is_offline(hash) then
|
||||
local afk_text = afk:get_afk_text(hash)
|
||||
|
||||
-- calculate afk time
|
||||
local timestamp = redis:hget(hash, 'time')
|
||||
local current_timestamp = msg.date
|
||||
local afk_time = current_timestamp - timestamp
|
||||
local seconds = afk_time % 60
|
||||
local minutes = math.floor(afk_time / 60)
|
||||
local minutes = minutes % 60
|
||||
local hours = math.floor(afk_time / 3600)
|
||||
if minutes == 00 and hours == 00 then
|
||||
duration = seconds..' Sekunden'
|
||||
elseif hours == 00 and minutes ~= 00 then
|
||||
duration = string.format("%02d:%02d", minutes, seconds)..' Minuten'
|
||||
elseif hours ~= 00 then
|
||||
duration = string.format("%02d:%02d:%02d", hours, minutes, seconds)..' Stunden'
|
||||
end
|
||||
|
||||
redis:hset(hash, 'afk', false)
|
||||
if afk_text then
|
||||
redis:hset(hash, 'afk_text', false)
|
||||
local afk_text = afk_text:gsub("%*","")
|
||||
local afk_text = afk_text:gsub("_","")
|
||||
utilities.send_message(self, msg.chat.id, user_name..' ist wieder da (war: *'..afk_text..'* für '..duration..')!', true, nil, true)
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, user_name..' ist wieder da (war '..duration..' weg)!')
|
||||
end
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function afk:action(msg)
|
||||
if msg.chat.type == "private" then
|
||||
utilities.send_reply(self, msg, "Mir ist's egal, ob du AFK bist ._.")
|
||||
return
|
||||
end
|
||||
|
||||
local user_id = msg.from.id
|
||||
local chat_id = msg.chat.id
|
||||
local user_name = get_name(msg)
|
||||
local timestamp = msg.date
|
||||
|
||||
utilities.send_reply(self, msg, afk:switch_afk(user_name, user_id, chat_id, timestamp, matches[2]))
|
||||
end
|
||||
|
||||
return afk
|
@ -2,12 +2,12 @@ local app_store = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
app_store.triggers = {
|
||||
"itunes.apple.com/(.*)/app/(.*)/id(%d+)",
|
||||
"^!itunes (%d+)$",
|
||||
"^/itunes (%d+)$",
|
||||
"itunes.apple.com/app/id(%d+)"
|
||||
}
|
||||
|
75
miku/plugins/bImages.lua
Normal file
75
miku/plugins/bImages.lua
Normal file
@ -0,0 +1,75 @@
|
||||
local bImages = {}
|
||||
|
||||
local HTTPS = require('ssl.https')
|
||||
HTTPS.timeout = 10
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function bImages:init(config)
|
||||
if not cred_data.bing_search_key then
|
||||
print('Missing config value: bing_search_key.')
|
||||
print('bImages.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
bImages.triggers = {"^/nil$"}
|
||||
bImages.inline_triggers = {
|
||||
"^b (.*)"
|
||||
}
|
||||
end
|
||||
|
||||
local apikey = cred_data.bing_search_key
|
||||
local BASE_URL = 'https://api.cognitive.microsoft.com/bing/v5.0'
|
||||
|
||||
function bImages:getImages(query)
|
||||
local url = BASE_URL..'/images/search?q='..URL.escape(query)..'&count=50&mkt=de-de'
|
||||
local response_body = {}
|
||||
local request_constructor = {
|
||||
url = url,
|
||||
method = "GET",
|
||||
sink = ltn12.sink.table(response_body),
|
||||
redirect = false,
|
||||
headers = {
|
||||
["Ocp-Apim-Subscription-Key"] = apikey
|
||||
}
|
||||
}
|
||||
local ok, response_code, response_headers = HTTPS.request(request_constructor)
|
||||
if not ok then return end
|
||||
local images = JSON.decode(table.concat(response_body)).value
|
||||
if not images[1] then return end
|
||||
|
||||
|
||||
|
||||
local results = '['
|
||||
for n in pairs(images) do
|
||||
if images[n].encodingFormat == 'jpeg' then -- Inline-Querys MUST use JPEG photos!
|
||||
local photo_url = images[n].contentUrl
|
||||
local thumb_url = images[n].thumbnailUrl
|
||||
results = results..'{"type":"photo","id":"'..math.random(100000000000000000)..'","photo_url":"'..photo_url..'","thumb_url":"'..thumb_url..'","photo_width":'..images[n].width..',"photo_height":'..images[n].height..',"reply_markup":{"inline_keyboard":[[{"text":"Bing aufrufen","url":"'..images[n].webSearchUrl..'"},{"text":"Bild aufrufen","url":"'..photo_url..'"}]]}},'
|
||||
end
|
||||
end
|
||||
|
||||
local results = results:sub(0, -2)
|
||||
local results = results..']'
|
||||
cache_data('bImages', string.lower(query), results, 1209600, 'key')
|
||||
return results
|
||||
end
|
||||
|
||||
function bImages:inline_callback(inline_query, config, matches)
|
||||
local query = matches[1]
|
||||
local results = redis:get('telegram:cache:bImages:'..string.lower(query))
|
||||
if not results then
|
||||
results = bImages:getImages(query)
|
||||
end
|
||||
|
||||
if not results then return end
|
||||
utilities.answer_inline_query(self, inline_query, results, 3600)
|
||||
end
|
||||
|
||||
function bImages:action()
|
||||
end
|
||||
|
||||
return bImages
|
253
miku/plugins/banhammer.lua
Normal file
253
miku/plugins/banhammer.lua
Normal file
@ -0,0 +1,253 @@
|
||||
local banhammer = {}
|
||||
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
banhammer.command = 'banhammer <nur für Superuser>'
|
||||
|
||||
function banhammer:init(config)
|
||||
banhammer.triggers = {
|
||||
"^/(whitelist) (enable)$",
|
||||
"^/(whitelist) (disable)$",
|
||||
"^/(whitelist) (user) (%d+)$",
|
||||
"^/(whitelist) (chat)$",
|
||||
"^/(whitelist) (delete) (user) (%d+)$",
|
||||
"^/(whitelist) (delete) (chat)$",
|
||||
"^/(ban) (user) (%d+)$",
|
||||
"^/(ban) (delete) (%d+)$",
|
||||
"^/(kick) (%d+)$"
|
||||
}
|
||||
banhammer.doc = [[*
|
||||
]]..config.cmd_pat..[[whitelist* _<enable>_/_<disable>_: Aktiviert/deaktiviert Whitelist
|
||||
*]]..config.cmd_pat..[[whitelist* user _<user#id>_: Whiteliste User
|
||||
*]]..config.cmd_pat..[[whitelist* chat: Whiteliste ganze Gruppe
|
||||
*]]..config.cmd_pat..[[whitelist* delete user _<user#id>_: Lösche User von der Whitelist
|
||||
*]]..config.cmd_pat..[[whitelist* delete chat: Lösche ganze Gruppe von der Whitelist
|
||||
*]]..config.cmd_pat..[[ban* user _<user#id>_: Kicke User vom Chat und kicke ihn, wenn er erneut beitritt
|
||||
*]]..config.cmd_pat..[[ban* delete _<user#id>_: Entbanne User
|
||||
*]]..config.cmd_pat..[[kick* _<user#id>_: Kicke User aus dem Chat]]
|
||||
end
|
||||
|
||||
function banhammer:kick_user(user_id, chat_id, self, onlykick)
|
||||
if user_id == tostring(our_id) then
|
||||
return "Ich werde mich nicht selbst kicken!"
|
||||
else
|
||||
local request = bindings.request(self, 'kickChatMember', {
|
||||
chat_id = chat_id,
|
||||
user_id = user_id
|
||||
} )
|
||||
if onlykick then return end
|
||||
if not request then return 'User gebannt, aber kicken war nicht erfolgreich. Bin ich Administrator oder ist der User hier überhaupt?' end
|
||||
return 'User '..user_id..' gebannt!'
|
||||
end
|
||||
end
|
||||
|
||||
function banhammer:ban_user(user_id, chat_id, self)
|
||||
if user_id == tostring(our_id) then
|
||||
return "Ich werde mich nicht selbst kicken!"
|
||||
else
|
||||
-- Save to redis
|
||||
local hash = 'banned:'..chat_id..':'..user_id
|
||||
redis:set(hash, true)
|
||||
-- Kick from chat
|
||||
return banhammer:kick_user(user_id, chat_id, self)
|
||||
end
|
||||
end
|
||||
|
||||
function banhammer:unban_user(user_id, chat_id, self, chat_type)
|
||||
local hash = 'banned:'..chat_id..':'..user_id
|
||||
redis:del(hash)
|
||||
if chat_type == 'supergroup' then -- how can bots be admins anyway?
|
||||
local request = bindings.request(self, 'unbanChatMember', {
|
||||
chat_id = chat_id,
|
||||
user_id = user_id
|
||||
} )
|
||||
end
|
||||
return 'User '..user_id..' wurde entbannt.'
|
||||
end
|
||||
|
||||
function banhammer:is_banned(user_id, chat_id)
|
||||
local hash = 'banned:'..chat_id..':'..user_id
|
||||
local banned = redis:get(hash)
|
||||
return banned or false
|
||||
end
|
||||
|
||||
function banhammer:is_user_whitelisted(id)
|
||||
local hash = 'whitelist:user#id'..id
|
||||
local white = redis:get(hash) or false
|
||||
return white
|
||||
end
|
||||
|
||||
function banhammer:is_chat_whitelisted(id)
|
||||
local hash = 'whitelist:chat#id'..id
|
||||
local white = redis:get(hash) or false
|
||||
return white
|
||||
end
|
||||
|
||||
function banhammer:pre_process(msg, self, config)
|
||||
-- SERVICE MESSAGE
|
||||
if msg.new_chat_member then
|
||||
local user_id = msg.new_chat_member.id
|
||||
print('Checking invited user '..user_id)
|
||||
local banned = banhammer:is_banned(user_id, msg.chat.id)
|
||||
if banned then
|
||||
print('User is banned!')
|
||||
banhammer:kick_user(user_id, msg.chat.id, self, true)
|
||||
end
|
||||
-- No further checks
|
||||
return msg
|
||||
end
|
||||
|
||||
-- BANNED USER TALKING
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
local user_id = msg.from.id
|
||||
local chat_id = msg.chat.id
|
||||
local banned = banhammer:is_banned(user_id, chat_id)
|
||||
if banned then
|
||||
print('Banned user talking!')
|
||||
banhammer:ban_user(user_id, chat_id, self)
|
||||
msg.text = ''
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- WHITELIST
|
||||
local hash = 'whitelist:enabled'
|
||||
local whitelist = redis:get(hash)
|
||||
local issudo = is_sudo(msg, config)
|
||||
|
||||
-- Allow all sudo users even if whitelist is allowed
|
||||
if whitelist and not issudo then
|
||||
print('Whitelist enabled and not sudo')
|
||||
-- Check if user or chat is whitelisted
|
||||
local allowed = banhammer:is_user_whitelisted(msg.from.id)
|
||||
local has_been_warned = redis:hget('user:'..msg.from.id, 'has_been_warned')
|
||||
|
||||
if not allowed then
|
||||
print('User '..msg.from.id..' not whitelisted')
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
allowed = banhammer:is_chat_whitelisted(msg.chat.id)
|
||||
if not allowed then
|
||||
print ('Chat '..msg.chat.id..' not whitelisted')
|
||||
else
|
||||
print ('Chat '..msg.chat.id..' whitelisted :)')
|
||||
end
|
||||
else
|
||||
if not has_been_warned then
|
||||
utilities.send_reply(self, msg, "Dies ist ein privater Bot, der erst nach einer Freischaltung benutzt werden kann.\nThis is a private bot, which can only be after an approval.")
|
||||
redis:hset('user:'..msg.from.id, 'has_been_warned', true)
|
||||
else
|
||||
print('User has already been warned!')
|
||||
end
|
||||
end
|
||||
else
|
||||
print('User '..msg.from.id..' allowed :)')
|
||||
end
|
||||
|
||||
if not allowed then
|
||||
msg.text = ''
|
||||
msg.text_lower = ''
|
||||
msg.entities = ''
|
||||
end
|
||||
|
||||
-- else
|
||||
-- print('Whitelist not enabled or is sudo')
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function banhammer:action(msg, config, matches)
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'ban' then
|
||||
local user_id = matches[3]
|
||||
local chat_id = msg.chat.id
|
||||
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
if matches[2] == 'user' then
|
||||
local text = banhammer:ban_user(user_id, chat_id, self)
|
||||
utilities.send_reply(self, msg, text)
|
||||
return
|
||||
end
|
||||
if matches[2] == 'delete' then
|
||||
local text = banhammer:unban_user(user_id, chat_id, self, msg.chat.type)
|
||||
utilities.send_reply(self, msg, text)
|
||||
return
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Das ist keine Chat-Gruppe')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if matches[1] == 'kick' then
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
banhammer:kick_user(matches[2], msg.chat.id, self, true)
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Das ist keine Chat-Gruppe')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if matches[1] == 'whitelist' then
|
||||
if matches[2] == 'enable' then
|
||||
local hash = 'whitelist:enabled'
|
||||
redis:set(hash, true)
|
||||
utilities.send_reply(self, msg, 'Whitelist aktiviert')
|
||||
return
|
||||
end
|
||||
|
||||
if matches[2] == 'disable' then
|
||||
local hash = 'whitelist:enabled'
|
||||
redis:del(hash)
|
||||
utilities.send_reply(self, msg, 'Whitelist deaktiviert')
|
||||
return
|
||||
end
|
||||
|
||||
if matches[2] == 'user' then
|
||||
local hash = 'whitelist:user#id'..matches[3]
|
||||
redis:set(hash, true)
|
||||
utilities.send_reply(self, msg, 'User '..matches[3]..' whitelisted')
|
||||
return
|
||||
end
|
||||
|
||||
if matches[2] == 'chat' then
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
local hash = 'whitelist:chat#id'..msg.chat.id
|
||||
redis:set(hash, true)
|
||||
utilities.send_reply(self, msg, 'Chat '..msg.chat.id..' whitelisted')
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Das ist keine Chat-Gruppe!')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if matches[2] == 'delete' and matches[3] == 'user' then
|
||||
local hash = 'whitelist:user#id'..matches[4]
|
||||
redis:del(hash)
|
||||
utilities.send_reply(self, msg, 'User '..matches[4]..' von der Whitelist entfernt!')
|
||||
return
|
||||
end
|
||||
|
||||
if matches[2] == 'delete' and matches[3] == 'chat' then
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
local hash = 'whitelist:chat#id'..msg.chat.id
|
||||
redis:del(hash)
|
||||
utilities.send_reply(self, msg, 'Chat '..msg.chat.id..' von der Whitelist entfernt')
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, 'Das ist keine Chat-Gruppe!')
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return banhammer
|
@ -2,8 +2,8 @@ local bitly = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function bitly:init(config)
|
||||
if not cred_data.bitly_access_token then
|
@ -4,10 +4,10 @@ local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local OAuth = require "OAuth"
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function bitly_create:init(config)
|
||||
if not cred_data.bitly_client_id then
|
||||
@ -25,7 +25,7 @@ function bitly_create:init(config)
|
||||
end
|
||||
|
||||
bitly_create.triggers = {
|
||||
"^/short (auth) (.+)$",
|
||||
"^/short(auth)(.+)$",
|
||||
"^/short (auth)$",
|
||||
"^/short (unauth)$",
|
||||
"^/short (me)$",
|
||||
@ -93,12 +93,16 @@ function bitly_create:action(msg, config, matches)
|
||||
|
||||
if matches[1] == 'auth' and matches[2] then
|
||||
utilities.send_reply(self, msg, bitly_create:get_bitly_access_token(hash, matches[2]), true)
|
||||
local message_id = redis:hget(hash, 'bitly_login_msg')
|
||||
utilities.edit_message(self, msg.chat.id, message_id, '*Anmeldung abgeschlossen!*', true, true)
|
||||
redis:hdel(hash, 'bitly_login_msg')
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'auth' then
|
||||
utilities.send_reply(self, msg, 'Bitte logge dich ein und folge den Anweisungen:\n[Bei Bitly anmelden](https://bitly.com/oauth/authorize?client_id='..client_id..'&redirect_uri='..redirect_uri..')', true)
|
||||
return
|
||||
local result = utilities.send_reply(self, msg, '*Bitte logge dich ein und folge den Anweisungen.*', true, '{"inline_keyboard":[[{"text":"Bei Bitly anmelden","url":"https://bitly.com/oauth/authorize?client_id='..client_id..'&redirect_uri='..redirect_uri..'&state='..self.info.username..'"}]]}')
|
||||
redis:hset(hash, 'bitly_login_msg', result.result.message_id)
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'unauth' and bitly_access_token then
|
||||
@ -127,7 +131,7 @@ function bitly_create:action(msg, config, matches)
|
||||
print('Not signed in, will use global bitly access_token')
|
||||
bitly_access_token = cred_data.bitly_access_token
|
||||
end
|
||||
|
||||
|
||||
if matches[2] == nil then
|
||||
long_url = url_encode(matches[1])
|
||||
domain = 'bit.ly'
|
51
miku/plugins/br.lua
Normal file
51
miku/plugins/br.lua
Normal file
@ -0,0 +1,51 @@
|
||||
local br = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
br.triggers = {
|
||||
"br.de/nachrichten/(.*).html$"
|
||||
}
|
||||
|
||||
function br:get_br_article(article)
|
||||
local url = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url=%22http://www.br.de/nachrichten/'..article..'.html%22%20and%20xpath=%22//div[@id=%27content%27]/div[1]/div[2]/div[1]|//div[@class=%27lead_picture%27]/img%22&format=json'
|
||||
local res,code = https.request(url)
|
||||
local data = json.decode(res).query.results
|
||||
if code ~= 200 then return "HTTP-Fehler" end
|
||||
if not data then return "HTTP-Fehler" end
|
||||
|
||||
local subtitle = data.div.h1.em
|
||||
local title = string.sub(data.div.h1.content, 3)
|
||||
local teaser = string.sub(data.div.p[1].content, 2)
|
||||
if data.div.p[3] then
|
||||
updated = data.div.p[3].content
|
||||
else
|
||||
updated = data.div.p[2].content
|
||||
end
|
||||
if data.img then
|
||||
image_url = 'https://www.br.de'..data.img.src
|
||||
end
|
||||
local text = '*'..subtitle..' - '..title..'*'..teaser..'\n_'..updated..'_'
|
||||
|
||||
if data.img then
|
||||
return text, image_url
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
function br:action(msg, config, matches)
|
||||
local article = URL.escape(matches[1])
|
||||
local text, image_url = br:get_br_article(article)
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url, 'br_teaser.jpg')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return br
|
40
miku/plugins/btc.lua
Normal file
40
miku/plugins/btc.lua
Normal file
@ -0,0 +1,40 @@
|
||||
local btc = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function btc:init(config)
|
||||
btc.triggers = {
|
||||
"^/btc$"
|
||||
}
|
||||
btc.doc = [[*
|
||||
]]..config.cmd_pat..[[btc*: Zeigt aktuellen Bitcoin-Kurs an]]
|
||||
end
|
||||
|
||||
btc.command = 'btc'
|
||||
|
||||
-- See https://bitcoinaverage.com/api
|
||||
function btc:getBTCX()
|
||||
local base_url = 'https://api.bitcoinaverage.com/ticker/global/'
|
||||
-- Do request on bitcoinaverage, the final / is critical!
|
||||
local res,code = https.request(base_url.."EUR/")
|
||||
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
local ask = string.gsub(data.ask, "%.", ",")
|
||||
local bid = string.gsub(data.bid, "%.", ",")
|
||||
|
||||
-- Easy, it's right there
|
||||
text = 'BTC/EUR\n'..'*Kaufen:* '..ask..'\n'..'*Verkaufen:* '..bid
|
||||
return text
|
||||
end
|
||||
|
||||
|
||||
function btc:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, btc:getBTCX(cur), true)
|
||||
end
|
||||
|
||||
return btc
|
39
miku/plugins/calc.lua
Normal file
39
miku/plugins/calc.lua
Normal file
@ -0,0 +1,39 @@
|
||||
local calc = {}
|
||||
|
||||
local URL = require('socket.url')
|
||||
local http = require('socket.http')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
calc.command = 'calc <Ausdruck>'
|
||||
|
||||
function calc:init(config)
|
||||
calc.triggers = {
|
||||
"^/calc (.*)$"
|
||||
}
|
||||
calc.doc = [[*
|
||||
]]..config.cmd_pat..[[calc* _[Ausdruck]_: Rechnet]]
|
||||
end
|
||||
|
||||
function calc:mathjs(exp)
|
||||
local exp = string.gsub(exp, ",", "%.")
|
||||
local url = 'http://api.mathjs.org/v1/'
|
||||
url = url..'?expr='..URL.escape(exp)
|
||||
local b,c = http.request(url)
|
||||
local text = nil
|
||||
if c == 200 then
|
||||
text = '= '..string.gsub(b, "%.", ",")
|
||||
|
||||
elseif c == 400 then
|
||||
text = b
|
||||
else
|
||||
text = 'Unerwarteter Fehler\n'
|
||||
..'Ist api.mathjs.org erreichbar?'
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
function calc:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, calc:mathjs(matches[1]))
|
||||
end
|
||||
|
||||
return calc
|
39
miku/plugins/cats.lua
Normal file
39
miku/plugins/cats.lua
Normal file
@ -0,0 +1,39 @@
|
||||
local cats = {}
|
||||
|
||||
local HTTP = require('socket.http')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
cats.command = 'cat [gif]'
|
||||
|
||||
function cats:init(config)
|
||||
if not cred_data.cat_apikey then
|
||||
print('Missing config value: cat_apikey.')
|
||||
print('cats.lua will be enabled, but there are more features with a key.')
|
||||
end
|
||||
|
||||
cats.triggers = {
|
||||
"^/cat$",
|
||||
"^/cat (gif)$"
|
||||
}
|
||||
|
||||
cats.doc = [[*
|
||||
]]..config.cmd_pat..[[cat*: Postet eine zufällige Katze
|
||||
*]]..config.cmd_pat..[[cat* _gif_: Postet eine zufällige, animierte Katze]]
|
||||
end
|
||||
|
||||
|
||||
local apikey = cred_data.cat_apikey or "" -- apply for one here: http://thecatapi.com/api-key-registration.html
|
||||
|
||||
function cats:action(msg, config)
|
||||
if matches[1] == 'gif' then
|
||||
local url = 'http://thecatapi.com/api/images/get?type=gif&apikey='..apikey
|
||||
local file = download_to_file(url, 'miau.gif')
|
||||
utilities.send_document(self, msg.chat.id, file, nil, msg.message_id)
|
||||
else
|
||||
local url = 'http://thecatapi.com/api/images/get?type=jpg,png&apikey='..apikey
|
||||
local file = download_to_file(url, 'miau.png')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
end
|
||||
|
||||
return cats
|
63
miku/plugins/channel.lua
Normal file
63
miku/plugins/channel.lua
Normal file
@ -0,0 +1,63 @@
|
||||
local channel = {}
|
||||
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
channel.command = 'ch <Kanal> \\n <Nachricht>'
|
||||
channel.doc = [[*
|
||||
/ch*_ <Kanal>_
|
||||
_<Nachricht>_
|
||||
|
||||
Sendet eine Nachricht in den Kanal. Der Kanal kann per Username oder ID bestimmt werden, Markdown wird unterstützt. Du musst Administrator oder Besitzer des Kanals sein.
|
||||
|
||||
Markdown-Syntax:
|
||||
*Fetter Text*
|
||||
_Kursiver Text_
|
||||
[Text](URL)
|
||||
`Inline-Codeblock`
|
||||
```Größere Code-Block über mehrere Zeilen```
|
||||
|
||||
*Der Kanalname muss mit einem @ beginnen!*]]
|
||||
|
||||
function channel:init(config)
|
||||
channel.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('ch', true).table
|
||||
end
|
||||
|
||||
function channel:action(msg, config)
|
||||
local input = utilities.input(msg.text)
|
||||
local output
|
||||
if input then
|
||||
local chat_id = utilities.get_word(input, 1)
|
||||
local admin_list, t = bindings.getChatAdministrators(self, { chat_id = chat_id } )
|
||||
if admin_list then
|
||||
local is_admin = false
|
||||
for _, admin in ipairs(admin_list.result) do
|
||||
if admin.user.id == msg.from.id then
|
||||
is_admin = true
|
||||
end
|
||||
end
|
||||
if is_admin then
|
||||
local text = input:match('\n(.+)')
|
||||
if text then
|
||||
local success, result = utilities.send_message(self, chat_id, text, true, nil, true)
|
||||
if success then
|
||||
output = 'Deine Nachricht wurde versendet!'
|
||||
else
|
||||
output = 'Sorry, ich konnte deine Nachricht nicht senden.\n`' .. result.description .. '`'
|
||||
end
|
||||
else
|
||||
output = 'Bitte gebe deine Nachricht ein. Markdown wird unterstützt.'
|
||||
end
|
||||
else
|
||||
output = 'Es sieht nicht so aus, als wärst du der Administrator dieses Kanals.'
|
||||
end
|
||||
else
|
||||
output = 'Sorry, ich konnte die Administratorenliste nicht abrufen. Falls du den Kanalnamen benutzt: Beginnt er mit einem @?\n`' .. t.description .. '`'
|
||||
end
|
||||
else
|
||||
output = channel.doc
|
||||
end
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return channel
|
90
miku/plugins/channels.lua
Normal file
90
miku/plugins/channels.lua
Normal file
@ -0,0 +1,90 @@
|
||||
local channels = {}
|
||||
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
channels.command = 'channel <nur für Superuser>'
|
||||
|
||||
function channels:init(config)
|
||||
channels.triggers = {
|
||||
"^/channel? (enable)",
|
||||
"^/channel? (disable)"
|
||||
}
|
||||
channels.doc = [[*
|
||||
]]..config.cmd_pat..[[channel* _<enable>_/_<disable>_: Aktiviert/deaktiviert den Bot im Chat]]
|
||||
end
|
||||
|
||||
-- Checks if bot was disabled on specific chat
|
||||
function channels:is_channel_disabled(msg)
|
||||
local hash = 'chat:'..msg.chat.id..':disabled'
|
||||
local disabled = redis:get(hash)
|
||||
|
||||
if not disabled or disabled == "false" then
|
||||
return false
|
||||
end
|
||||
|
||||
return disabled
|
||||
end
|
||||
|
||||
function channels:enable_channel(msg)
|
||||
local hash = 'chat:'..msg.chat.id..':disabled'
|
||||
local disabled = redis:get(hash)
|
||||
if disabled then
|
||||
print('Setting redis variable '..hash..' to false')
|
||||
redis:set(hash, false)
|
||||
return 'Channel aktiviert'
|
||||
else
|
||||
return 'Channel ist nicht deaktiviert!'
|
||||
end
|
||||
end
|
||||
|
||||
function channels:disable_channel(msg)
|
||||
local hash = 'chat:'..msg.chat.id..':disabled'
|
||||
local disabled = redis:get(hash)
|
||||
if disabled ~= "true" then
|
||||
print('Setting redis variable '..hash..' to true')
|
||||
redis:set(hash, true)
|
||||
return 'Channel deaktiviert'
|
||||
else
|
||||
return 'Channel ist bereits deaktiviert!'
|
||||
end
|
||||
end
|
||||
|
||||
function channels:pre_process(msg, self, config)
|
||||
-- If is sudo can reeanble the channel
|
||||
if is_sudo(msg, config) then
|
||||
if msg.text == "/channel enable" then
|
||||
channels:enable_channel(msg)
|
||||
end
|
||||
end
|
||||
|
||||
if channels:is_channel_disabled(msg) then
|
||||
print('Channel wurde deaktiviert')
|
||||
msg.text = ''
|
||||
msg.text_lower = ''
|
||||
msg.entities = ''
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function channels:action(msg, config, matches)
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
|
||||
-- Enable a channel
|
||||
if matches[1] == 'enable' then
|
||||
utilities.send_reply(self, msg, channels:enable_channel(msg))
|
||||
return
|
||||
end
|
||||
-- Disable a channel
|
||||
if matches[1] == 'disable' then
|
||||
utilities.send_reply(self, msg, channels:disable_channel(msg))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return channels
|
35
miku/plugins/cleverbot.lua
Normal file
35
miku/plugins/cleverbot.lua
Normal file
@ -0,0 +1,35 @@
|
||||
local cleverbot = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
local json = require('dkjson')
|
||||
|
||||
function cleverbot:init(config)
|
||||
cleverbot.triggers = {
|
||||
"^/cbot (.*)$"
|
||||
}
|
||||
|
||||
cleverbot.doc = [[*
|
||||
]]..config.cmd_pat..[[cbot* _<Text>_*: Befragt den Cleverbot]]
|
||||
end
|
||||
|
||||
cleverbot.command = 'cbot <Text>'
|
||||
|
||||
function cleverbot:action(msg, config)
|
||||
local text = msg.text
|
||||
local url = "https://brawlbot.tk/apis/chatter-bot-api/cleverbot.php?text="..URL.escape(text)
|
||||
local query = https.request(url)
|
||||
if query == nil then utilities.send_reply(self, msg, 'Ein Fehler ist aufgetreten :(') return end
|
||||
local decode = json.decode(query)
|
||||
local answer = string.gsub(decode.clever, "Ä", "Ä")
|
||||
local answer = string.gsub(answer, "ä", "ä")
|
||||
local answer = string.gsub(answer, "Ö", "Ö")
|
||||
local answer = string.gsub(answer, "ö", "ö")
|
||||
local answer = string.gsub(answer, "Ü", "Ü")
|
||||
local answer = string.gsub(answer, "ü", "ü")
|
||||
local answer = string.gsub(answer, "ß", "ß")
|
||||
utilities.send_reply(self, msg, answer)
|
||||
end
|
||||
|
||||
return cleverbot
|
33
miku/plugins/clypit.lua
Normal file
33
miku/plugins/clypit.lua
Normal file
@ -0,0 +1,33 @@
|
||||
local clypit = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
clypit.triggers = {
|
||||
"clyp.it/([A-Za-z0-9-_-]+)"
|
||||
}
|
||||
|
||||
function clypit:get_clypit_details(shortcode)
|
||||
local BASE_URL = "http://api.clyp.it"
|
||||
local url = BASE_URL..'/'..shortcode
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
|
||||
local title = data.Title
|
||||
local duration = data.Duration
|
||||
|
||||
local audio = download_to_file(data.Mp3Url)
|
||||
return audio, title, duration
|
||||
end
|
||||
|
||||
function clypit:action(msg, config, matches)
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_audio')
|
||||
local audio, title, duration = clypit:get_clypit_details(matches[1])
|
||||
if not audio then return utilities.send_reply(self, msg, config.errors.connection) end
|
||||
utilities.send_audio(self, msg.chat.id, audio, nil, msg.message_id, duration, nil, title)
|
||||
end
|
||||
|
||||
return clypit
|
@ -1,14 +1,14 @@
|
||||
local control = {}
|
||||
|
||||
local bot = require('otouto.bot')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bot = require('miku.bot')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
local cmd_pat -- Prevents the command from being uncallable.
|
||||
|
||||
function control:init(config)
|
||||
cmd_pat = config.cmd_pat
|
||||
control.triggers = utilities.triggers(self.info.username, cmd_pat,
|
||||
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table
|
||||
{'^'..cmd_pat..'script'}):t('restart', true):t('halt').table
|
||||
end
|
||||
|
||||
function control:action(msg, config)
|
||||
@ -17,25 +17,25 @@ function control:action(msg, config)
|
||||
return
|
||||
end
|
||||
|
||||
if msg.date < os.time() - 1 then return end
|
||||
if msg.date < os.time() - 2 then return end
|
||||
|
||||
if msg.text_lower:match('^'..cmd_pat..'reload') then
|
||||
if msg.text_lower:match('^'..cmd_pat..'restart') then
|
||||
for pac, _ in pairs(package.loaded) do
|
||||
if pac:match('^otouto%.plugins%.') then
|
||||
if pac:match('^miku%.plugins%.') then
|
||||
package.loaded[pac] = nil
|
||||
end
|
||||
end
|
||||
package.loaded['otouto.bindings'] = nil
|
||||
package.loaded['otouto.utilities'] = nil
|
||||
package.loaded['miku.bindings'] = nil
|
||||
package.loaded['miku.utilities'] = nil
|
||||
package.loaded['config'] = nil
|
||||
if msg.text_lower:match('%+config') then for k, v in pairs(require('config')) do
|
||||
config[k] = v
|
||||
end end
|
||||
bot.init(self, config)
|
||||
utilities.send_reply(self, msg, 'Bot reloaded!')
|
||||
utilities.send_reply(self, msg, 'Bot neu gestartet!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'halt') then
|
||||
self.is_started = false
|
||||
utilities.send_reply(self, msg, 'Stopping bot!')
|
||||
utilities.send_reply(self, msg, 'Stoppe Bot!')
|
||||
elseif msg.text_lower:match('^'..cmd_pat..'script') then
|
||||
local input = msg.text_lower:match('^'..cmd_pat..'script\n(.+)')
|
||||
if not input then
|
||||
@ -46,7 +46,7 @@ function control:action(msg, config)
|
||||
for command in input:gmatch('(.-)\n') do
|
||||
command = utilities.trim(command)
|
||||
msg.text = command
|
||||
bot.on_msg_receive(self, msg)
|
||||
bot.on_msg_receive(self, msg, config)
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,7 @@
|
||||
local creds_manager = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function creds_manager:init(config)
|
||||
creds_manager.triggers = {
|
64
miku/plugins/currency.lua
Normal file
64
miku/plugins/currency.lua
Normal file
@ -0,0 +1,64 @@
|
||||
local currency = {}
|
||||
|
||||
local HTTPS = require('ssl.https')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
currency.command = 'cash [Menge] <von> <zu>'
|
||||
|
||||
function currency:init(config)
|
||||
currency.triggers = {
|
||||
"^/cash ([A-Za-z]+)$",
|
||||
"^/cash ([A-Za-z]+) ([A-Za-z]+)$",
|
||||
"^/cash (%d+[%d%.,]*) ([A-Za-z]+) ([A-Za-z]+)$",
|
||||
"^(/eur)$"
|
||||
}
|
||||
currency.doc = [[*
|
||||
]]..config.cmd_pat..[[cash* _[Menge]_ _<von>_ _<zu>_
|
||||
Beispiel: _]]..config.cmd_pat..[[cash 5 USD EUR_]]
|
||||
end
|
||||
|
||||
function currency:action(msg, config)
|
||||
if not matches[2] then
|
||||
from = string.upper(matches[1])
|
||||
to = 'EUR'
|
||||
amount = 1
|
||||
elseif matches[3] then
|
||||
from = string.upper(matches[2])
|
||||
to = string.upper(matches[3])
|
||||
amount = matches[1]
|
||||
else
|
||||
from = string.upper(matches[1])
|
||||
to = string.upper(matches[2])
|
||||
amount = 1
|
||||
end
|
||||
|
||||
local amount = string.gsub(amount, ",", ".")
|
||||
amount = tonumber(amount)
|
||||
local result = 1
|
||||
local BASE_URL = 'https://www.google.com/finance/converter'
|
||||
if from == to then
|
||||
utilities.send_reply(self, msg, 'Jaja, sehr witzig...')
|
||||
return
|
||||
end
|
||||
|
||||
local url = BASE_URL..'?from='..from..'&to='..to..'&a='..amount
|
||||
local str, res = HTTPS.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local str = str:match('<span class=bld>(.*) %u+</span>')
|
||||
if not str then
|
||||
utilities.send_reply(self, msg, 'Keine gültige Währung - sieh dir die Währungsliste bei [Google Finanzen](https://www.google.com/finance/converter) an.', true)
|
||||
return
|
||||
end
|
||||
local result = string.format('%.2f', str)
|
||||
local result = string.gsub(result, "%.", ",")
|
||||
|
||||
local amount = tostring(string.gsub(amount, "%.", ","))
|
||||
local output = amount..' '..from..' = *'..result..' '..to..'*'
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return currency
|
31
miku/plugins/dailymotion.lua
Normal file
31
miku/plugins/dailymotion.lua
Normal file
@ -0,0 +1,31 @@
|
||||
local dailymotion = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
dailymotion.triggers = {
|
||||
"dailymotion.com/video/([A-Za-z0-9-_-]+)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'https://api.dailymotion.com'
|
||||
|
||||
function dailymotion:send_dailymotion_info (dm_code)
|
||||
local url = BASE_URL..'/video/'..dm_code
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
|
||||
local title = data.title
|
||||
local channel = data.channel
|
||||
local text = '*'..title..'*\nHochgeladen in die Kategorie *'..channel..'*'
|
||||
return text
|
||||
end
|
||||
|
||||
function dailymotion:action(msg, config, matches)
|
||||
local text = dailymotion:send_dailymotion_info(matches[1])
|
||||
if not text then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return dailymotion
|
52
miku/plugins/deviantart.lua
Normal file
52
miku/plugins/deviantart.lua
Normal file
@ -0,0 +1,52 @@
|
||||
local deviantart = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
deviantart.triggers = {
|
||||
"http://(.*).deviantart.com/art/(.*)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'https://backend.deviantart.com'
|
||||
|
||||
function deviantart:get_da_data (da_code)
|
||||
local url = BASE_URL..'/oembed?url='..da_code
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
return data
|
||||
end
|
||||
|
||||
function deviantart:send_da_data (data)
|
||||
local title = data.title
|
||||
local category = data.category
|
||||
local author_name = data.author_name
|
||||
local text = title..' von '..author_name..'\n'..category
|
||||
|
||||
if data.rating == "adult" then
|
||||
return title..' von '..author_name..'\n'..category..'\n(NSFW)'
|
||||
else
|
||||
local image_url = data.fullsize_url
|
||||
if image_url == nil then
|
||||
image_url = data.url
|
||||
end
|
||||
local file = download_to_file(image_url)
|
||||
return text, file
|
||||
end
|
||||
end
|
||||
|
||||
function deviantart:action(msg, config, matches)
|
||||
local data = deviantart:get_da_data('http://'..matches[1]..'.deviantart.com/art/'..matches[2])
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
local text, file = deviantart:send_da_data(data)
|
||||
if file then
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
else
|
||||
utilities.send_reply(self, msg, text)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return deviantart
|
38
miku/plugins/dhl.lua
Normal file
38
miku/plugins/dhl.lua
Normal file
@ -0,0 +1,38 @@
|
||||
local dhl = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function dhl:init(config)
|
||||
dhl.triggers = {
|
||||
"/dhl (%d+)$"
|
||||
}
|
||||
dhl.doc = [[*
|
||||
]]..config.cmd_pat..[[dhl* _<Sendungsnummer>_: Aktueller Status der Sendung]]
|
||||
end
|
||||
|
||||
|
||||
local BASE_URL = 'https://mobil.dhl.de'
|
||||
|
||||
function dhl:sendungsstatus(id)
|
||||
local url = BASE_URL..'/shipmentdetails.html?shipmentId='..id
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "Fehler beim Abrufen von mobil.dhl.de" end
|
||||
local status = string.match(res, "<div id%=\"detailShortStatus\">(.-)</div>")
|
||||
local status = all_trim(status)
|
||||
local zeit = string.match(res, "<div id%=\"detailStatusDateTime\">(.-)</div>")
|
||||
local zeit = all_trim(zeit)
|
||||
if not zeit or zeit == '<br />' then
|
||||
return status
|
||||
end
|
||||
return '*'..status..'*\n_Stand: '..zeit..'_'
|
||||
end
|
||||
|
||||
function dhl:action(msg, config, matches)
|
||||
local sendungs_id = matches[1]
|
||||
if string.len(sendungs_id) < 8 then return end
|
||||
utilities.send_reply(self, msg, dhl:sendungsstatus(sendungs_id), true)
|
||||
end
|
||||
|
||||
return dhl
|
39
miku/plugins/dropbox.lua
Normal file
39
miku/plugins/dropbox.lua
Normal file
@ -0,0 +1,39 @@
|
||||
-- Doesn't use the API for now, maybe we can integrate some cool features?
|
||||
|
||||
local dropbox = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
dropbox.triggers = {
|
||||
"dropbox.com/s/([a-z0-9]+)/(.*)"
|
||||
}
|
||||
|
||||
function dropbox:action(msg, config, matches)
|
||||
local folder = matches[1]
|
||||
local file = string.gsub(matches[2], "?dl=0", "")
|
||||
local link = 'https://dl.dropboxusercontent.com/s/'..folder..'/'..file
|
||||
|
||||
local v,code = https.request(link)
|
||||
if code == 200 then
|
||||
if string.ends(link, ".png") or string.ends(link, ".jpe?g")then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(link)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
return
|
||||
elseif string.ends(link, ".webp") or string.ends(link, ".gif") then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(link)
|
||||
utilities.send_document(self, msg.chat.id, file, nil, msg.message_id)
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, link)
|
||||
end
|
||||
return
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return dropbox
|
42
miku/plugins/echo.lua
Normal file
42
miku/plugins/echo.lua
Normal file
@ -0,0 +1,42 @@
|
||||
local echo = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
echo.command = 'echo <Text>'
|
||||
|
||||
function echo:init(config)
|
||||
echo.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('echo', true).table
|
||||
echo.inline_triggers = {
|
||||
"^e (.*)"
|
||||
}
|
||||
echo.doc = [[*
|
||||
]]..config.cmd_pat..[[echo* _<Text>_: Gibt den Text aus]]
|
||||
end
|
||||
|
||||
function echo:inline_callback(inline_query, config, matches)
|
||||
local text = matches[1]
|
||||
local results = '['
|
||||
|
||||
-- enable custom markdown button
|
||||
if text:match('%[.*%]%(.*%)') or text:match('%*.*%*') or text:match('_.*_') or text:match('`.*`') then
|
||||
results = results..'{"type":"article","id":"'..math.random(100000000000000000)..'","thumb_url":"https://anditest.perseus.uberspace.de/inlineQuerys/echo/custom.jpg","title":"Eigenes Markdown","description":"'..text..'","input_message_content":{"message_text":"'..text..'","parse_mode":"Markdown"}},'
|
||||
end
|
||||
|
||||
local results = results..'{"type":"article","id":"'..math.random(100000000000000000)..'","thumb_url":"https://anditest.perseus.uberspace.de/inlineQuerys/echo/fett.jpg","title":"Fett","description":"*'..text..'*","input_message_content":{"message_text":"*'..text..'*","parse_mode":"Markdown"}},{"type":"article","id":"'..math.random(100000000000000000)..'","thumb_url":"https://anditest.perseus.uberspace.de/inlineQuerys/echo/kursiv.jpg","title":"Kursiv","description":"_'..text..'_","input_message_content":{"message_text":"_'..text..'_","parse_mode":"Markdown"}},{"type":"article","id":"'..math.random(100000000000000000)..'","thumb_url":"https://anditest.perseus.uberspace.de/inlineQuerys/echo/fixedsys.jpg","title":"Feste Breite","description":"`'..text..'`","input_message_content":{"message_text":"`'..text..'`","parse_mode":"Markdown"}}]'
|
||||
utilities.answer_inline_query(self, inline_query, results, 0)
|
||||
end
|
||||
|
||||
function echo:action(msg)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
utilities.send_message(self, msg.chat.id, echo.doc, true, msg.message_id, true)
|
||||
else
|
||||
local output
|
||||
if msg.chat.type == 'supergroup' then
|
||||
output = '*Echo:*\n"' .. utilities.md_escape(input) .. '"'
|
||||
end
|
||||
utilities.send_message(self, msg.chat.id, input, true, nil, true)
|
||||
end
|
||||
end
|
||||
|
||||
return echo
|
57
miku/plugins/entergroup.lua
Normal file
57
miku/plugins/entergroup.lua
Normal file
@ -0,0 +1,57 @@
|
||||
local entergroup = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
entergroup.triggers = {
|
||||
'/nil'
|
||||
}
|
||||
|
||||
function entergroup:chat_new_user(msg, self)
|
||||
local user_name = msg.new_chat_member.first_name
|
||||
local chat_title = msg.chat.title
|
||||
if msg.from.username then
|
||||
at_name = ' (@'..msg.from.username..')'
|
||||
else
|
||||
at_name = ''
|
||||
end
|
||||
if msg.from.id == msg.new_chat_member.id then -- entered through link
|
||||
added_by = ''
|
||||
else
|
||||
added_by = '\n'..msg.from.name..at_name..' hat dich hinzugefügt!'
|
||||
end
|
||||
if msg.new_chat_member.id == self.info.id then -- don't say hello to ourselves
|
||||
return
|
||||
end
|
||||
local text = 'Hallo '..user_name..', willkommen bei *'..chat_title..'*!'..added_by
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
function entergroup:chat_del_user(msg, self)
|
||||
if msg.left_chat_member.id == msg.from.id then -- silent ignore, if user wasn't kicked
|
||||
return
|
||||
end
|
||||
local user_name = msg.left_chat_member.first_name
|
||||
if msg.from.username then
|
||||
at_name = ' (@'..msg.from.username..')'
|
||||
else
|
||||
at_name = ''
|
||||
end
|
||||
local text = user_name..' wurde von '..msg.from.first_name..at_name..' aus der Gruppe gekickt.'
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
function entergroup:pre_process(msg, self)
|
||||
if msg.new_chat_member then
|
||||
entergroup:chat_new_user(msg, self)
|
||||
elseif msg.left_chat_member then
|
||||
entergroup:chat_del_user(msg, self)
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function entergroup:action(msg)
|
||||
end
|
||||
|
||||
return entergroup
|
@ -1,7 +1,7 @@
|
||||
local expand = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function expand:init(config)
|
||||
expand.triggers = {
|
@ -4,9 +4,9 @@ local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function facebook:init(config)
|
||||
if not cred_data.fb_access_token then
|
||||
@ -53,7 +53,7 @@ function facebook:fb_post (id, story_id)
|
||||
local message = data.message
|
||||
local name = data.name
|
||||
if data.link then
|
||||
link = '\n'..data.name..':\n'..data.link
|
||||
link = '\n'..data.name..':\n'..utilities.md_escape(data.link)
|
||||
else
|
||||
link = ""
|
||||
end
|
||||
@ -76,7 +76,7 @@ function facebook:send_facebook_photo(photo_id, receiver)
|
||||
|
||||
local from = '*'..data.from.name..'*'
|
||||
if data.name then
|
||||
text = from..' hat ein Bild gepostet:\n'..data.name
|
||||
text = from..' hat ein Bild gepostet:\n'..utilities.md_escape(data.name)
|
||||
else
|
||||
text = from..' hat ein Bild gepostet:'
|
||||
end
|
||||
@ -93,12 +93,7 @@ function facebook:send_facebook_video(video_id)
|
||||
local from = '*'..data.from.name..'*'
|
||||
local description = data.description
|
||||
local source = data.source
|
||||
if data.title then
|
||||
text = from..' hat ein Video gepostet:\n'..description..'\n['..data.title..']('..source..')'
|
||||
else
|
||||
text = from..' hat ein Video gepostet:\n'..description..'\n'..utilities.md_escape(source)
|
||||
end
|
||||
return text
|
||||
return from..' hat ein Video gepostet:\n'..description, source, data.title
|
||||
end
|
||||
|
||||
function facebook:facebook_info(name)
|
||||
@ -156,9 +151,10 @@ function facebook:action(msg, config, matches)
|
||||
else
|
||||
photo_id = matches[4]
|
||||
end
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local text, image_url = facebook:send_facebook_photo(photo_id, receiver)
|
||||
local file = download_to_file(image_url)
|
||||
if not image_url then return end
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url, 'photo.jpg')
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
return
|
||||
@ -168,8 +164,14 @@ function facebook:action(msg, config, matches)
|
||||
else
|
||||
video_id = matches[3]
|
||||
end
|
||||
local output = facebook:send_facebook_video(video_id)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
local output, video_url, title = facebook:send_facebook_video(video_id)
|
||||
if not title then
|
||||
title = 'Video aufrufen'
|
||||
else
|
||||
title = 'VIDEO: '..title
|
||||
end
|
||||
if not video_url then return end
|
||||
utilities.send_reply(self, msg, output, true, '{"inline_keyboard":[[{"text":"'..utilities.md_escape(title)..'","url":"'..video_url..'"}]]}')
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, facebook:facebook_info(matches[1]), true)
|
36
miku/plugins/fefe.lua
Normal file
36
miku/plugins/fefe.lua
Normal file
@ -0,0 +1,36 @@
|
||||
local fefe = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
fefe.triggers = {
|
||||
"blog.fefe.de/%?ts=%w%w%w%w%w%w%w%w"
|
||||
}
|
||||
|
||||
function fefe:post(id)
|
||||
local url = 'http://'..id
|
||||
local results, code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-Fehler" end
|
||||
if string.match(results, "No entries found.") then return "Eintrag nicht gefunden." end
|
||||
|
||||
local line = string.sub( results, string.find(results, "<li><a href[^\n]+"))
|
||||
local text = line:gsub("<div style=.+", "")
|
||||
-- remove link at begin
|
||||
local text = text:gsub("<li><a href=\"%?ts=%w%w%w%w%w%w%w%w\">%[l]</a>", "")
|
||||
-- replace "<p>" with newline; "<b>" and "</b>" with "*"
|
||||
local text = text:gsub("<p>", "\n\n"):gsub("<p u>", "\n\n")
|
||||
local text = text:gsub("<b>", "*"):gsub("</b>", "*")
|
||||
local text = text:gsub("<i>", "_"):gsub("</i>", "_")
|
||||
-- format quotes and links markdown-like
|
||||
local text = text:gsub("<a href=\"", "("):gsub("\">", ")["):gsub("</a>", "]")
|
||||
local text = text:gsub("<blockquote>", "\n\n> "):gsub("</blockquote>", "\n\n")
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function fefe:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, fefe:post(matches[1]))
|
||||
end
|
||||
|
||||
return fefe
|
76
miku/plugins/flickr.lua
Normal file
76
miku/plugins/flickr.lua
Normal file
@ -0,0 +1,76 @@
|
||||
local flickr = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function flickr:init(config)
|
||||
if not cred_data.flickr_apikey then
|
||||
print('Missing config value: flickr_apikey.')
|
||||
print('flickr.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
flickr.triggers = {
|
||||
"flickr.com/photos/([A-Za-z0-9-_-]+)/([0-9]+)"
|
||||
}
|
||||
end
|
||||
|
||||
local BASE_URL = 'https://api.flickr.com/services/rest'
|
||||
|
||||
local makeOurDate = function(dateString)
|
||||
local pattern = "(%d+)%-(%d+)%-(%d+) (%d+)%:(%d+)%:(%d+)"
|
||||
local year, month, day, hours, minutes, seconds = dateString:match(pattern)
|
||||
return day..'.'..month..'.'..year..' um '..hours..':'..minutes..':'..seconds..' Uhr'
|
||||
end
|
||||
|
||||
function flickr:get_flickr_photo_data (photo_id)
|
||||
local apikey = cred_data.flickr_apikey
|
||||
local url = BASE_URL..'/?method=flickr.photos.getInfo&api_key='..apikey..'&photo_id='..photo_id..'&format=json&nojsoncallback=1'
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res).photo
|
||||
return data
|
||||
end
|
||||
|
||||
function flickr:send_flickr_photo_data(data)
|
||||
local title = data.title._content
|
||||
local username = data.owner.username
|
||||
local taken = data.dates.taken
|
||||
local views = data.views
|
||||
if data.usage.candownload == 1 then
|
||||
local text = '"'..title..'", aufgenommen am '..makeOurDate(taken)..' von '..username..' ('..comma_value(data.views)..' Aufrufe)'
|
||||
local image_url = 'https://farm'..data.farm..'.staticflickr.com/'..data.server..'/'..data.id..'_'..data.originalsecret..'_o_d.'..data.originalformat
|
||||
if data.originalformat == 'gif' then
|
||||
return text, image_url, true
|
||||
else
|
||||
return text, image_url
|
||||
end
|
||||
else
|
||||
return '"'..title..'", aufgenommen '..taken..' von '..username..' ('..data.views..' Aufrufe)\nBild konnte nicht gedownloadet werden (Keine Berechtigung)'
|
||||
end
|
||||
end
|
||||
|
||||
function flickr:action(msg, config, matches)
|
||||
local data = flickr:get_flickr_photo_data(matches[2])
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
local text, image_url, isgif = flickr:send_flickr_photo_data(data)
|
||||
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
if isgif then
|
||||
utilities.send_document(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
else
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
end
|
||||
else
|
||||
utilities.send_reply(self, msg, text)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return flickr
|
53
miku/plugins/flickr_search.lua
Normal file
53
miku/plugins/flickr_search.lua
Normal file
@ -0,0 +1,53 @@
|
||||
local flickr_search = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function flickr_search:init(config)
|
||||
if not cred_data.flickr_apikey then
|
||||
print('Missing config value: flickr_apikey.')
|
||||
print('flickr_search.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
flickr_search.triggers = {
|
||||
"^/flickr (.*)$"
|
||||
}
|
||||
end
|
||||
|
||||
flickr_search.command = 'flickr <Suchbegriff>'
|
||||
|
||||
local apikey = cred_data.flickr_apikey
|
||||
local BASE_URL = 'https://api.flickr.com/services/rest'
|
||||
|
||||
function flickr_search:get_flickr (term)
|
||||
local url = BASE_URL..'/?method=flickr.photos.search&api_key='..apikey..'&format=json&nojsoncallback=1&privacy_filter=1&safe_search=3&extras=url_o&text='..term
|
||||
local b,c = https.request(url)
|
||||
if c ~= 200 then return nil end
|
||||
local photo = json.decode(b).photos.photo
|
||||
-- truly randomize
|
||||
math.randomseed(os.time())
|
||||
-- random max json table size
|
||||
local i = math.random(#photo)
|
||||
local link_image = photo[i].url_o
|
||||
return link_image
|
||||
end
|
||||
|
||||
function flickr_search:action(msg, config, matches)
|
||||
local url = flickr_search:get_flickr(matches[1])
|
||||
if not url then utilities.send_reply(self, msg, config.errors.results) return end
|
||||
|
||||
local file = download_to_file(url)
|
||||
|
||||
if string.ends(url, ".gif") then
|
||||
utilities.send_document(self, msg.chat.id, file, url)
|
||||
return
|
||||
else
|
||||
utilities.send_photo(self, msg.chat.id, file, url)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return flickr_search
|
@ -3,9 +3,9 @@ local forecast = {}
|
||||
local HTTPS = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function forecast:init(config)
|
||||
if not cred_data.forecastio_apikey then
|
||||
@ -36,7 +36,7 @@ function forecast:init(config)
|
||||
]]
|
||||
end
|
||||
|
||||
forecast.command = 'forecast'
|
||||
forecast.command = 'f [Ort]'
|
||||
|
||||
local BASE_URL = "https://api.forecast.io/forecast"
|
||||
local apikey = cred_data.forecastio_apikey
|
242
miku/plugins/gImages.lua
Normal file
242
miku/plugins/gImages.lua
Normal file
@ -0,0 +1,242 @@
|
||||
-- You need a Google API key and a Google Custom Search Engine set up to use this, in config.google_api_key and config.google_cse_key, respectively.
|
||||
-- You must also sign up for the CSE in the Google Developer Console, and enable image results.
|
||||
|
||||
local gImages = {}
|
||||
|
||||
local HTTPS = require('ssl.https')
|
||||
HTTPS.timeout = 10
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function gImages:init(config)
|
||||
if not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('gImages.lua will not be enabled.')
|
||||
return
|
||||
elseif not cred_data.google_cse_id then
|
||||
print('Missing config value: google_cse_id.')
|
||||
print('gImages.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
gImages.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('img', true):t('i', true).table
|
||||
gImages.doc = [[*
|
||||
]]..config.cmd_pat..[[img* _<Suchbegriff>_
|
||||
Sucht Bild mit Google und versendet es (SafeSearch aktiv)
|
||||
Alias: *]]..config.cmd_pat..[[i*]]
|
||||
end
|
||||
|
||||
gImages.command = 'img <Suchbegriff>'
|
||||
|
||||
-- Yes, the callback is copied from below, but I can't think of another method :\
|
||||
function gImages:callback(callback, msg, self, config, input)
|
||||
if not msg then return end
|
||||
utilities.answer_callback_query(self, callback, 'Suche nochmal nach "'..URL.unescape(input)..'"')
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local hash = 'telegram:cache:gImages'
|
||||
local results = redis:smembers(hash..':'..string.lower(URL.unescape(input)))
|
||||
|
||||
if not results[1] then
|
||||
print('doing web request')
|
||||
results = gImages:get_image(input)
|
||||
if results == 403 then
|
||||
utilities.send_reply(self, msg, config.errors.quotaexceeded, true)
|
||||
return
|
||||
elseif not results then
|
||||
utilities.send_reply(self, msg, config.errors.results, true)
|
||||
return
|
||||
end
|
||||
gImages:cache_result(results, input)
|
||||
end
|
||||
|
||||
-- Random image from table
|
||||
local i = math.random(#results)
|
||||
|
||||
-- Thanks to Amedeo for this!
|
||||
local failed = true
|
||||
local nofTries = 0
|
||||
|
||||
while failed and nofTries < #results do
|
||||
if results[i].image then
|
||||
img_url = results[i].link
|
||||
mimetype = results[i].mime
|
||||
context = results[i].image.contextLink
|
||||
else -- from cache
|
||||
img_url = results[i]
|
||||
mimetype = redis:hget(hash..':'..img_url, 'mime')
|
||||
context = redis:hget(hash..':'..img_url, 'contextLink')
|
||||
end
|
||||
|
||||
-- It's important to save the image with the right ending!
|
||||
if mimetype == 'image/gif' then
|
||||
file = download_to_file(img_url, 'img.gif')
|
||||
elseif mimetype == 'image/png' then
|
||||
file = download_to_file(img_url, 'img.png')
|
||||
elseif mimetype == 'image/jpeg' then
|
||||
file = download_to_file(img_url, 'img.jpg')
|
||||
else
|
||||
file = nil
|
||||
end
|
||||
|
||||
if not file then
|
||||
nofTries = nofTries + 1
|
||||
i = i+1
|
||||
if i > #results then
|
||||
i = 1
|
||||
end
|
||||
else
|
||||
failed = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if failed then
|
||||
utilities.send_reply(self, msg, 'Fehler beim Herunterladen eines Bildes.', true, '{"inline_keyboard":[[{"text":"Nochmal versuchen","callback_data":"@'..self.info.username..' gImages:'..input..'"}]]}')
|
||||
return
|
||||
end
|
||||
|
||||
if mimetype == 'image/gif' then
|
||||
result = utilities.send_document(self, msg.chat.id, file, nil, msg.message_id, '{"inline_keyboard":[[{"text":"Seite aufrufen","url":"'..context..'"},{"text":"Bild aufrufen","url":"'..img_url..'"},{"text":"Nochmal suchen","callback_data":"@'..self.info.username..' gImages:'..input..'"}]]}')
|
||||
else
|
||||
result = utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id, '{"inline_keyboard":[[{"text":"Seite aufrufen","url":"'..context..'"},{"text":"Bild aufrufen","url":"'..img_url..'"},{"text":"Nochmal suchen","callback_data":"@'..self.info.username..' gImages:'..input..'"}]]}')
|
||||
end
|
||||
|
||||
if not result then
|
||||
utilities.send_reply(self, msg, config.errors.connection, true, '{"inline_keyboard":[[{"text":"Nochmal versuchen","callback_data":"@'..self.info.username..' gImages:'..input..'"}]]}')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function gImages:get_image(input)
|
||||
local apikey = cred_data.google_apikey -- 100 requests is RIDICULOUS, Google!
|
||||
local cseid = cred_data.google_cse_id
|
||||
local BASE_URL = 'https://www.googleapis.com/customsearch/v1'
|
||||
local url = BASE_URL..'/?searchType=image&alt=json&num=10&key='..apikey..'&cx='..cseid..'&safe=high'..'&q=' .. input .. '&fields=items(link,mime,image(contextLink))'
|
||||
local jstr, res = HTTPS.request(url)
|
||||
local jdat = JSON.decode(jstr).items
|
||||
|
||||
if not jdat then
|
||||
return 'NORESULTS'
|
||||
end
|
||||
|
||||
if jdat.error then
|
||||
if jdat.error.code == 403 then
|
||||
return 403
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return jdat
|
||||
end
|
||||
|
||||
function gImages:cache_result(results, text)
|
||||
local cache = {}
|
||||
for v in pairs(results) do
|
||||
table.insert(cache, results[v].link)
|
||||
end
|
||||
for n, link in pairs(cache) do
|
||||
redis:hset('telegram:cache:gImages:'..link, 'mime', results[n].mime)
|
||||
redis:hset('telegram:cache:gImages:'..link, 'contextLink', results[n].image.contextLink)
|
||||
redis:expire('telegram:cache:gImages:'..link, 1209600)
|
||||
end
|
||||
cache_data('gImages', string.lower(text), cache, 1209600, 'set')
|
||||
end
|
||||
|
||||
function gImages:action(msg, config, matches)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, gImages.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
print ('Checking if search contains blacklisted word: '..input)
|
||||
if is_blacklisted(input) then
|
||||
utilities.send_reply(self, msg, 'Vergiss es! ._.')
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
|
||||
local hash = 'telegram:cache:gImages'
|
||||
local results = redis:smembers(hash..':'..string.lower(input))
|
||||
|
||||
if not results[1] then
|
||||
print('doing web request')
|
||||
results = gImages:get_image(URL.escape(input))
|
||||
if results == 403 then
|
||||
utilities.send_reply(self, msg, config.errors.quotaexceeded, true)
|
||||
return
|
||||
elseif not results or results == 'NORESULTS' then
|
||||
utilities.send_reply(self, msg, config.errors.results, true)
|
||||
return
|
||||
end
|
||||
gImages:cache_result(results, input)
|
||||
end
|
||||
|
||||
-- Random image from table
|
||||
local i = math.random(#results)
|
||||
|
||||
-- Thanks to Amedeo for this!
|
||||
local failed = true
|
||||
local nofTries = 0
|
||||
|
||||
while failed and nofTries < #results do
|
||||
if results[i].image then
|
||||
img_url = results[i].link
|
||||
mimetype = results[i].mime
|
||||
context = results[i].image.contextLink
|
||||
else -- from cache
|
||||
img_url = results[i]
|
||||
mimetype = redis:hget(hash..':'..img_url, 'mime')
|
||||
context = redis:hget(hash..':'..img_url, 'contextLink')
|
||||
end
|
||||
|
||||
-- It's important to save the image with the right ending!
|
||||
if mimetype == 'image/gif' then
|
||||
file = download_to_file(img_url, 'img.gif')
|
||||
elseif mimetype == 'image/png' then
|
||||
file = download_to_file(img_url, 'img.png')
|
||||
elseif mimetype == 'image/jpeg' then
|
||||
file = download_to_file(img_url, 'img.jpg')
|
||||
else
|
||||
file = nil
|
||||
end
|
||||
|
||||
if not file then
|
||||
nofTries = nofTries + 1
|
||||
i = i+1
|
||||
if i > #results then
|
||||
i = 1
|
||||
end
|
||||
else
|
||||
failed = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if failed then
|
||||
utilities.send_reply(self, msg, 'Fehler beim Herunterladen eines Bildes.', true, '{"inline_keyboard":[[{"text":"Nochmal versuchen","callback_data":"@'..self.info.username..' gImages:'..URL.escape(input)..'"}]]}')
|
||||
return
|
||||
end
|
||||
|
||||
if mimetype == 'image/gif' then
|
||||
result = utilities.send_document(self, msg.chat.id, file, nil, msg.message_id, '{"inline_keyboard":[[{"text":"Seite aufrufen","url":"'..context..'"},{"text":"Bild aufrufen","url":"'..img_url..'"},{"text":"Nochmal suchen","callback_data":"@'..self.info.username..' gImages:'..URL.escape(input)..'"}]]}')
|
||||
else
|
||||
result = utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id, '{"inline_keyboard":[[{"text":"Seite aufrufen","url":"'..context..'"},{"text":"Bild aufrufen","url":"'..img_url..'"},{"text":"Nochmal suchen","callback_data":"@'..self.info.username..' gImages:'..URL.escape(input)..'"}]]}')
|
||||
end
|
||||
|
||||
if not result then
|
||||
utilities.send_reply(self, msg, config.errors.connection, true, '{"inline_keyboard":[[{"text":"Nochmal versuchen","callback_data":"@'..self.info.username..' gImages:'..URL.escape(input)..'"}]]}')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return gImages
|
43
miku/plugins/gMaps.lua
Normal file
43
miku/plugins/gMaps.lua
Normal file
@ -0,0 +1,43 @@
|
||||
local gMaps = {}
|
||||
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
gMaps.command = 'loc <Ort>'
|
||||
|
||||
function gMaps:init(config)
|
||||
gMaps.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('loc', true).table
|
||||
gMaps.doc = [[*
|
||||
]]..config.cmd_pat..[[loc* _<Ort>_: Sendet Ort via Google Maps]]
|
||||
end
|
||||
|
||||
function gMaps:get_staticmap(area, lat, lon)
|
||||
local base_api = "https://maps.googleapis.com/maps/api"
|
||||
local url = base_api .. "/staticmap?size=600x300&zoom=12¢er="..URL.escape(area).."&markers=color:red"..URL.escape("|"..area)
|
||||
|
||||
local file = download_to_file(url)
|
||||
return file
|
||||
end
|
||||
|
||||
function gMaps:action(msg, config)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, gMaps.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
utilities.send_typing(self, msg.chat.id, 'find_location')
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_location(self, msg.chat.id, coords.lat, coords.lon, msg.message_id)
|
||||
utilities.send_photo(self, msg.chat.id, gMaps:get_staticmap(input, coords.lat, coords.lon), nil, msg.message_id)
|
||||
end
|
||||
|
||||
return gMaps
|
@ -3,17 +3,15 @@ local gSearch = {}
|
||||
local HTTPS = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
gSearch.command = 'google <query>'
|
||||
gSearch.command = 'google <Suchbegriff>'
|
||||
|
||||
function gSearch:init(config)
|
||||
gSearch.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('g', true):t('google', true):t('gnsfw', true).table
|
||||
gSearch.doc = [[```
|
||||
]]..config.cmd_pat..[[google <Suchbegriff>
|
||||
Sendet Suchergebnisse von Google
|
||||
Alias: ]]..config.cmd_pat..[[g
|
||||
```]]
|
||||
gSearch.doc = [[*
|
||||
]]..config.cmd_pat..[[google* _<Suchbegriff>_: Sendet Suchergebnisse von Google
|
||||
Alias: _]]..config.cmd_pat..[[g_]]
|
||||
end
|
||||
|
||||
function gSearch:googlethat(query, config)
|
||||
@ -27,8 +25,7 @@ function gSearch:googlethat(query, config)
|
||||
-- Do the request
|
||||
local res, code = HTTPS.request(api..parameters)
|
||||
if code == 403 then
|
||||
utilities.send_reply(self, msg, config.errors.quotaexceeded)
|
||||
return
|
||||
return '403'
|
||||
end
|
||||
if code ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
@ -69,8 +66,18 @@ function gSearch:action(msg, config)
|
||||
end
|
||||
end
|
||||
|
||||
local results, stats = gSearch:googlethat(input, config)
|
||||
utilities.send_message(self, msg.chat.id, gSearch:stringlinks(results, stats), true, nil, true)
|
||||
local results, stats = gSearch:googlethat(input, onfig)
|
||||
if results == '403' then
|
||||
utilities.send_reply(self, msg, config.errors.quotaexceeded)
|
||||
return
|
||||
end
|
||||
|
||||
if not results then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, gSearch:stringlinks(results, stats), true, nil, true, '{"inline_keyboard":[[{"text":"Alle Ergebnisse anzeigen","url":"https://www.google.com/search?q='..URL.escape(input)..'"}]]}')
|
||||
|
||||
end
|
||||
|
147
miku/plugins/games.lua
Normal file
147
miku/plugins/games.lua
Normal file
@ -0,0 +1,147 @@
|
||||
local games = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local URL = require('socket.url')
|
||||
local xml = require("xml")
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
games.command = 'game <Spiel>'
|
||||
|
||||
function games:init(config)
|
||||
games.triggers = {
|
||||
"^/game (.+)$"
|
||||
}
|
||||
games.doc = [[*
|
||||
]]..config.cmd_pat..[[game*_ <Spiel>_: Sendet Infos zum Spiel]]
|
||||
end
|
||||
|
||||
local BASE_URL = 'http://thegamesdb.net/api'
|
||||
|
||||
local makeOurDate = function(dateString)
|
||||
local pattern = "(%d+)%/(%d+)%/(%d+)"
|
||||
local month, day, year = dateString:match(pattern)
|
||||
return day..'.'..month..'.'..year
|
||||
end
|
||||
|
||||
|
||||
function games:get_game_id(game)
|
||||
local url = BASE_URL..'/GetGamesList.php?name='..game
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local result = xml.load(res)
|
||||
if xml.find(result, 'id') then
|
||||
local game = xml.find(result, 'id')[1]
|
||||
return game
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function games:send_game_photo(result, self, msg)
|
||||
local BASE_URL = xml.find(result, 'baseImgUrl')[1]
|
||||
local images = {}
|
||||
|
||||
if xml.find(result, 'fanart') then
|
||||
local fanart = xml.find(result, 'fanart')[1]
|
||||
local fanrt_url = BASE_URL..fanart[1]
|
||||
table.insert(images, fanrt_url)
|
||||
end
|
||||
|
||||
if xml.find(result, 'boxart', 'side', 'front') then
|
||||
local boxart = xml.find(result, 'boxart', 'side', 'front')[1]
|
||||
local boxart_url = BASE_URL..boxart
|
||||
table.insert(images, boxart_url)
|
||||
end
|
||||
|
||||
local i = 0
|
||||
for k, v in pairs(images) do
|
||||
i = i+1
|
||||
local file = download_to_file(v, 'game'..i..'.jpg')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
end
|
||||
|
||||
function games:send_game_data(game_id, self, msg)
|
||||
local url = BASE_URL..'/GetGame.php?id='..game_id
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local result = xml.load(res)
|
||||
|
||||
local title = xml.find(result, 'GameTitle')[1]
|
||||
local platform = xml.find(result, 'Platform')[1]
|
||||
|
||||
if xml.find(result, 'ReleaseDate') then
|
||||
date = ', erschienen am '..makeOurDate(xml.find(result, 'ReleaseDate')[1])
|
||||
else
|
||||
date = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'Overview') then
|
||||
desc = '\n_'..string.sub(xml.find(result, 'Overview')[1], 1, 200) .. '..._'
|
||||
else
|
||||
desc = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'Genres') then
|
||||
local genres = xml.find(result, 'Genres')
|
||||
local genre_count = tablelength(genres)-1
|
||||
if genre_count == 1 then
|
||||
genre = '\nGenre: '..genres[1][1]
|
||||
else
|
||||
local genre_loop = '\nGenres: '
|
||||
for v in pairs(genres) do
|
||||
if v == 'xml' then break; end
|
||||
if v < genre_count then
|
||||
genre_loop = genre_loop..genres[v][1]..', '
|
||||
else
|
||||
genre_loop = genre_loop..genres[v][1]
|
||||
end
|
||||
end
|
||||
genre = genre_loop
|
||||
end
|
||||
else
|
||||
genre = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'Players') then
|
||||
players = '\nSpieler: '..xml.find(result, 'Players')[1]
|
||||
else
|
||||
players = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'Youtube') then
|
||||
video = '\n[Video auf YouTube ansehen]('..xml.find(result, 'Youtube')[1]..')'
|
||||
else
|
||||
video = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'Publisher') then
|
||||
publisher = '\nPublisher: '..xml.find(result, 'Publisher')[1]
|
||||
else
|
||||
publisher = ''
|
||||
end
|
||||
|
||||
local text = '*'..title..'* für *'..platform..'*'..date..desc..genre..players..video..publisher
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
|
||||
if xml.find(result, 'fanrt') or xml.find(result, 'boxart') then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
games:send_game_photo(result, self, msg)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
function games:action(msg, config, matches)
|
||||
local game = URL.escape(matches[1])
|
||||
local game_id = games:get_game_id(game)
|
||||
if not game_id then
|
||||
utilities.send_reply(self, msg, 'Spiel nicht gefunden!')
|
||||
return
|
||||
else
|
||||
games:send_game_data(game_id, self, msg)
|
||||
end
|
||||
end
|
||||
|
||||
return games
|
99
miku/plugins/gdrive.lua
Normal file
99
miku/plugins/gdrive.lua
Normal file
@ -0,0 +1,99 @@
|
||||
local gdrive = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local https = require('ssl.https')
|
||||
local ltn12 = require('ltn12')
|
||||
local json = require('dkjson')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function gdrive:init(config)
|
||||
if not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('gdrive.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
gdrive.triggers = {
|
||||
"docs.google.com/(.*)/d/([A-Za-z0-9-_-]+)",
|
||||
"drive.google.com/(.*)/d/([A-Za-z0-9-_-]+)",
|
||||
"drive.google.com/(open)%?id=([A-Za-z0-9-_-]+)"
|
||||
}
|
||||
end
|
||||
|
||||
local apikey = cred_data.google_apikey
|
||||
|
||||
local BASE_URL = 'https://www.googleapis.com/drive/v2'
|
||||
|
||||
function gdrive:get_drive_document_data (docid)
|
||||
local apikey = cred_data.google_apikey
|
||||
local url = BASE_URL..'/files/'..docid..'?key='..apikey..'&fields=id,title,mimeType,ownerNames,exportLinks,fileExtension'
|
||||
local res,code = https.request(url)
|
||||
local res = string.gsub(res, 'image/', '')
|
||||
local res = string.gsub(res, 'application/', '')
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
return data
|
||||
end
|
||||
|
||||
function gdrive:send_drive_document_data(data, self, msg)
|
||||
local title = data.title
|
||||
local mimetype = data.mimeType
|
||||
local id = data.id
|
||||
local owner = data.ownerNames[1]
|
||||
local text = '"'..title..'", freigegeben von '..owner
|
||||
if data.exportLinks then
|
||||
if data.exportLinks.png then
|
||||
local image_url = data.exportLinks.png
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
else
|
||||
local pdf_url = data.exportLinks.pdf
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_document')
|
||||
local file = download_to_file(pdf_url)
|
||||
utilities.send_document(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
end
|
||||
else
|
||||
local get_file_url = 'https://drive.google.com/uc?id='..id
|
||||
local ext = data.fileExtension
|
||||
if mimetype == "png" or mimetype == "jpg" or mimetype == "jpeg" or mimetype == "gif" or mimetype == "webp" then
|
||||
local respbody = {}
|
||||
local options = {
|
||||
url = get_file_url,
|
||||
sink = ltn12.sink.table(respbody),
|
||||
redirect = false
|
||||
}
|
||||
local response = {https.request(options)} -- luasec doesn't support 302 redirects, so we must contact gdrive again
|
||||
local code = response[2]
|
||||
local headers = response[3]
|
||||
local file_url = headers.location
|
||||
if ext == "jpg" or ext == "jpeg" or ext == "png" then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(file_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
else
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_document')
|
||||
local file = download_to_file(file_url)
|
||||
utilities.send_document(self, msg.chat.id, file, text, msg.message_id)
|
||||
return
|
||||
end
|
||||
else
|
||||
local text = '*'..title..'*, freigegeben von _'..owner..'_\n[Direktlink]('..get_file_url..')'
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function gdrive:action(msg, config, matches)
|
||||
local docid = matches[2]
|
||||
local data = gdrive:get_drive_document_data(docid)
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
gdrive:send_drive_document_data(data, self, msg)
|
||||
return
|
||||
end
|
||||
|
||||
return gdrive
|
@ -1,7 +1,7 @@
|
||||
local get = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
get.command = 'get <Variable>'
|
||||
|
113
miku/plugins/getfile.lua
Normal file
113
miku/plugins/getfile.lua
Normal file
@ -0,0 +1,113 @@
|
||||
-- YOU NEED THE FOLLOWING FOLDERS: photo, document, video, voice
|
||||
-- PLEASE ADJUST YOUR PATH BELOW
|
||||
-- Save your bot api key in redis set telegram:credentials!
|
||||
|
||||
local media_download = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local ltn12 = require('ltn12')
|
||||
local HTTPS = require('ssl.https')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
media_download.triggers = {
|
||||
'/nil'
|
||||
}
|
||||
|
||||
function media_download:download_to_file_permanently(url, file_name)
|
||||
local respbody = {}
|
||||
local options = {
|
||||
url = url,
|
||||
sink = ltn12.sink.table(respbody),
|
||||
redirect = false
|
||||
}
|
||||
local response = nil
|
||||
response = {HTTPS.request(options)}
|
||||
|
||||
local code = response[2]
|
||||
local headers = response[3]
|
||||
local status = response[4]
|
||||
|
||||
if code ~= 200 then return false end
|
||||
|
||||
-- TODO: Save, when folder doesn't exist
|
||||
-- Create necessary folders in this folder!
|
||||
local file_path = "/home/YOURPATH/tmp/"..file_name
|
||||
file = io.open(file_path, "w+")
|
||||
file:write(table.concat(respbody))
|
||||
file:close()
|
||||
print("Downloaded to: "..file_path)
|
||||
return true
|
||||
end
|
||||
|
||||
function media_download:pre_process(msg, self)
|
||||
if msg.photo then
|
||||
local lv = #msg.photo -- find biggest photo, always the last value
|
||||
file_id = msg.photo[lv].file_id
|
||||
file_size = msg.photo[lv].file_size
|
||||
elseif msg.video then
|
||||
file_id = msg.video.file_id
|
||||
file_size = msg.video.file_size
|
||||
elseif msg.sticker then
|
||||
file_id = msg.sticker.file_id
|
||||
file_size = msg.sticker.file_size
|
||||
elseif msg.voice then
|
||||
file_id = msg.voice.file_id
|
||||
file_size = msg.voice.file_size
|
||||
elseif msg.audio then
|
||||
file_id = msg.audio.file_id
|
||||
file_size = msg.audio.file_size
|
||||
elseif msg.document then
|
||||
file_id = msg.document.file_id
|
||||
file_size = msg.document.file_size
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if file_size > 19922944 then
|
||||
print('File is over 20 MB - can\'t download :(')
|
||||
return
|
||||
end
|
||||
|
||||
-- Check if file has already been downloaded
|
||||
local already_downloaded = redis:sismember('telegram:file_id', file_id)
|
||||
if already_downloaded == true then
|
||||
print('File has already been downloaded in the past, skipping...')
|
||||
return
|
||||
end
|
||||
|
||||
-- Saving file to the Telegram Cloud
|
||||
local request = bindings.request(self, 'getFile', {
|
||||
file_id = file_id
|
||||
} )
|
||||
|
||||
-- Getting file from the Telegram Cloud
|
||||
if not request then
|
||||
print('Download failed!')
|
||||
return
|
||||
end
|
||||
|
||||
-- Use original filename for documents
|
||||
if msg.document then
|
||||
file_path = 'document/'..file_id..'-'..msg.document.file_name -- to not overwrite a file
|
||||
else
|
||||
file_path = request.result.file_path
|
||||
end
|
||||
|
||||
-- Construct what we want
|
||||
local download_url = 'https://api.telegram.org/file/bot'..cred_data.bot_api_key..'/'..request.result.file_path
|
||||
local ok = media_download:download_to_file_permanently(download_url, file_path)
|
||||
if not ok then
|
||||
print('Download failed!')
|
||||
return
|
||||
end
|
||||
|
||||
-- Save file_id to redis to prevent downloading the same file over and over when forwarding
|
||||
redis:sadd('telegram:file_id', file_id)
|
||||
return msg
|
||||
end
|
||||
|
||||
function media_download:action(msg)
|
||||
end
|
||||
|
||||
return media_download
|
36
miku/plugins/gfycat.lua
Normal file
36
miku/plugins/gfycat.lua
Normal file
@ -0,0 +1,36 @@
|
||||
-- Thanks to Akamaru for the API entrypoints and the initial idea
|
||||
|
||||
local gfycat = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
gfycat.triggers = {
|
||||
"gfycat.com/([A-Za-z0-9-_-]+)"
|
||||
}
|
||||
|
||||
function gfycat:send_gfycat_video(name, self, msg)
|
||||
local BASE_URL = "https://gfycat.com"
|
||||
local url = BASE_URL..'/cajax/get/'..name
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res).gfyItem
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_video')
|
||||
local file = download_to_file(data.webmUrl)
|
||||
if file == nil then
|
||||
send_reply(self, msg, 'Fehler beim Herunterladen von '..name)
|
||||
return
|
||||
else
|
||||
utilities.send_video(self, msg.chat.id, file, nil, msg.message_id)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function gfycat:action(msg, config, matches)
|
||||
local name = matches[1]
|
||||
gfycat:send_gfycat_video(name, self, msg)
|
||||
return
|
||||
end
|
||||
|
||||
return gfycat
|
@ -4,9 +4,9 @@ local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function github:init(config)
|
||||
github.triggers = {
|
||||
@ -31,9 +31,9 @@ end
|
||||
|
||||
function github:send_github_data(data)
|
||||
if not data.owner then return nil end
|
||||
local name = '*'..data.name..'*'
|
||||
local description = '_'..data.description..'_'
|
||||
local owner = data.owner.login
|
||||
local name = '*'..utilities.md_escape(data.name)..'*'
|
||||
local description = '_'..utilities.md_escape(data.description)..'_'
|
||||
local owner = utilities.md_escape(data.owner.login)
|
||||
local clone_url = data.clone_url
|
||||
if data.language == nil or data.language == "" then
|
||||
language = ''
|
||||
@ -57,7 +57,7 @@ end
|
||||
function github:send_gh_commit_data(gh_code, gh_commit_sha, data)
|
||||
if not data.committer then return nil end
|
||||
local committer = data.committer.name
|
||||
local message = data.message
|
||||
local message = utilities.md_escape(data.message)
|
||||
local text = '`'..gh_code..'@'..gh_commit_sha..'` von *'..committer..'*:\n'..message
|
||||
return text
|
||||
end
|
68
miku/plugins/golem.lua
Normal file
68
miku/plugins/golem.lua
Normal file
@ -0,0 +1,68 @@
|
||||
local golem = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function golem:init(config)
|
||||
if not cred_data.golem_apikey then
|
||||
print('Missing config value: golem_apikey.')
|
||||
print('golem.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
golem.triggers = {
|
||||
"golem.de/news/([A-Za-z0-9-_-]+)-(%d+).html"
|
||||
}
|
||||
end
|
||||
|
||||
local BASE_URL = 'http://api.golem.de/api'
|
||||
|
||||
function golem:get_golem_data (article_identifier)
|
||||
local apikey = cred_data.golem_apikey
|
||||
local url = BASE_URL..'/article/meta/'..article_identifier..'/?key='..apikey..'&format=json'
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res).data
|
||||
|
||||
local url = BASE_URL..'/article/images/'..article_identifier..'/?key='..apikey..'&format=json'
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local image_data = json.decode(res).data
|
||||
return data, image_data
|
||||
end
|
||||
|
||||
function golem:send_golem_data(data, image_data)
|
||||
local headline = '*'..data.headline..'*'
|
||||
if data.subheadline ~= "" then
|
||||
subheadline = '\n_'..data.subheadline..'_'
|
||||
else
|
||||
subheadline = ""
|
||||
end
|
||||
local subheadline = data.subheadline
|
||||
local abstracttext = data.abstracttext
|
||||
local text = headline..subheadline..'\n'..abstracttext
|
||||
if image_data[1] then
|
||||
image_url = image_data[1].native.url
|
||||
else
|
||||
image_url = data.leadimg.url
|
||||
end
|
||||
return text, image_url
|
||||
end
|
||||
|
||||
function golem:action(msg, config, matches)
|
||||
local article_identifier = matches[2]
|
||||
local data, image_data = golem:get_golem_data(article_identifier)
|
||||
if not data and not image_data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
local text, image_url = golem:send_golem_data(data, image_data)
|
||||
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return golem
|
47
miku/plugins/googl.lua
Normal file
47
miku/plugins/googl.lua
Normal file
@ -0,0 +1,47 @@
|
||||
local googl = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function googl:init(config)
|
||||
if not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('googl.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
googl.triggers = {
|
||||
"goo.gl/([A-Za-z0-9-_-/-/]+)"
|
||||
}
|
||||
end
|
||||
|
||||
local BASE_URL = 'https://www.googleapis.com/urlshortener/v1'
|
||||
|
||||
local makeOurDate = function(dateString)
|
||||
local pattern = "(%d+)%-(%d+)%-(%d+)"
|
||||
local year, month, day = dateString:match(pattern)
|
||||
return day..'.'..month..'.'..year
|
||||
end
|
||||
|
||||
function googl:send_googl_info (shorturl)
|
||||
local apikey = cred_data.google_apikey
|
||||
local url = BASE_URL..'/url?key='..apikey..'&shortUrl=http://goo.gl/'..shorturl..'&projection=FULL&fields=longUrl,created,analytics(allTime(shortUrlClicks))'
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res)
|
||||
|
||||
local longUrl = data.longUrl
|
||||
local shortUrlClicks = data.analytics.allTime.shortUrlClicks
|
||||
local created = makeOurDate(data.created)
|
||||
local text = longUrl..'\n'..shortUrlClicks..' mal geklickt (erstellt am '..created..')'
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function googl:action(msg, config, matches)
|
||||
local shorturl = matches[1]
|
||||
utilities.send_reply(self, msg, googl:send_googl_info(shorturl))
|
||||
end
|
||||
|
||||
return googl
|
38
miku/plugins/gps.lua
Normal file
38
miku/plugins/gps.lua
Normal file
@ -0,0 +1,38 @@
|
||||
local gps = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
gps.command = 'gps <Breitengrad>,<Längengrad>'
|
||||
|
||||
function gps:init(config)
|
||||
gps.triggers = {
|
||||
"^/gps ([^,]*)[,%s]([^,]*)$",
|
||||
"google.de/maps/@([^,]*)[,%s]([^,]*)",
|
||||
"google.com/maps/@([^,]*)[,%s]([^,]*)",
|
||||
"google.de/maps/place/@([^,]*)[,%s]([^,]*)",
|
||||
"google.com/maps/place/@([^,]*)[,%s]([^,]*)"
|
||||
}
|
||||
gps.doc = [[*
|
||||
]]..config.cmd_pat..[[gps* _<Breitengrad>_,_<Längengrad>_: Sendet Karte mit diesen Koordinaten]]
|
||||
end
|
||||
|
||||
function gps:action(msg, config, matches)
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local lat = matches[1]
|
||||
local lon = matches[2]
|
||||
|
||||
local zooms = {16, 18}
|
||||
|
||||
local urls = {}
|
||||
for i in ipairs(zooms) do
|
||||
local zoom = zooms[i]
|
||||
local url = "https://maps.googleapis.com/maps/api/staticmap?zoom=" .. zoom .. "&size=600x300&maptype=hybrid¢er=" .. lat .. "," .. lon .. "&markers=color:red%7Clabel:•%7C" .. lat .. "," .. lon
|
||||
local file = download_to_file(url, 'zoom_'..i..'.png')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
|
||||
utilities.send_location(self, msg.chat.id, lat, lon, msg.message_id)
|
||||
end
|
||||
|
||||
return gps
|
@ -4,7 +4,7 @@
|
||||
|
||||
local greetings = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function greetings:init(config)
|
||||
config.greetings = config.greetings or {
|
||||
@ -41,12 +41,16 @@ end
|
||||
|
||||
function greetings:action(msg, config)
|
||||
|
||||
local nick = self.database.users[msg.from.id_str].nickname or msg.from.first_name
|
||||
local nick = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
if self.database.userdata[tostring(msg.from.id)] then
|
||||
nick = self.database.userdata[tostring(msg.from.id)].nickname or nick
|
||||
end
|
||||
|
||||
for trigger,responses in pairs(config.greetings) do
|
||||
for _,response in pairs(responses) do
|
||||
if msg.text_lower:match(response..',? '..self.info.first_name:lower()) then
|
||||
utilities.send_message(self, msg.chat.id, utilities.latcyr(trigger:gsub('#NAME', nick)))
|
||||
local output = utilities.char.zwnj .. trigger:gsub('#NAME', nick)
|
||||
utilities.send_message(self, msg.chat.id, output)
|
||||
return
|
||||
end
|
||||
end
|
45
miku/plugins/hackernews.lua
Normal file
45
miku/plugins/hackernews.lua
Normal file
@ -0,0 +1,45 @@
|
||||
local hackernews = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
hackernews.triggers = {
|
||||
"news.ycombinator.com/item%?id=(%d+)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'https://hacker-news.firebaseio.com/v0'
|
||||
|
||||
function hackernews:send_hackernews_post (hn_code)
|
||||
local url = BASE_URL..'/item/'..hn_code..'.json'
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res)
|
||||
|
||||
local by = data.by
|
||||
local title = data.title
|
||||
|
||||
if data.url then
|
||||
url = '\n[Link besuchen]('..data.url..')'
|
||||
else
|
||||
url = ''
|
||||
end
|
||||
|
||||
if data.text then
|
||||
post = '\n'..unescape_html(data.text)
|
||||
post = string.gsub(post, '<p>', ' ')
|
||||
else
|
||||
post = ''
|
||||
end
|
||||
local text = '*'..title..'* von _'..by..'_'..post..url
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function hackernews:action(msg, config, matches)
|
||||
local hn_code = matches[1]
|
||||
utilities.send_reply(self, msg, hackernews:send_hackernews_post(hn_code), true)
|
||||
end
|
||||
|
||||
return hackernews
|
48
miku/plugins/heise.lua
Normal file
48
miku/plugins/heise.lua
Normal file
@ -0,0 +1,48 @@
|
||||
local heise = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
heise.triggers = {
|
||||
"heise.de/newsticker/meldung/(.*).html$"
|
||||
}
|
||||
|
||||
function heise:get_heise_article(article)
|
||||
local url = 'https://query.yahooapis.com/v1/public/yql?q=select%20content,src,strong%20from%20html%20where%20url=%22http://www.heise.de/newsticker/meldung/'..article..'.html%22%20and%20xpath=%22//div[@id=%27mitte_news%27]/article/header/h2|//div[@id=%27mitte_news%27]/article/div/p[1]/strong|//div[@id=%27mitte_news%27]/article/div/figure/img%22&format=json'
|
||||
local res,code = https.request(url)
|
||||
local data = json.decode(res).query.results
|
||||
if code ~= 200 then return "HTTP-Fehler" end
|
||||
|
||||
local title = data.h2
|
||||
if data.strong then
|
||||
teaser = '\n'..data.strong
|
||||
else
|
||||
teaser = ''
|
||||
end
|
||||
if data.img then
|
||||
image_url = 'https:'..data.img.src
|
||||
end
|
||||
local text = '*'..title..'*'..teaser
|
||||
|
||||
if data.img then
|
||||
return text, image_url
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
function heise:action(msg, config, matches)
|
||||
local article = URL.escape(matches[1])
|
||||
local text, image_url = heise:get_heise_article(article)
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url, 'heise_teaser.jpg')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return heise
|
13
miku/plugins/hello.lua
Normal file
13
miku/plugins/hello.lua
Normal file
@ -0,0 +1,13 @@
|
||||
local hello = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
hello.triggers = {
|
||||
"^[Ss][Aa][Gg] [Hh][Aa][Ll][Ll][Oo] [Zz][Uu] (.*)$"
|
||||
}
|
||||
|
||||
function hello:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, 'Hallo, '..matches[1]..'!')
|
||||
end
|
||||
|
||||
return hello
|
@ -3,17 +3,22 @@
|
||||
|
||||
local help = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
local help_text
|
||||
|
||||
function help:init(config)
|
||||
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hilfe', true):t('help', true).table
|
||||
end
|
||||
|
||||
function help:action(msg, config)
|
||||
|
||||
local commandlist = {}
|
||||
help_text = '*Verfügbare Befehle:*\n• '..config.cmd_pat
|
||||
|
||||
for _,plugin in ipairs(self.plugins) do
|
||||
if plugin.command then
|
||||
|
||||
table.insert(commandlist, plugin.command)
|
||||
--help_text = help_text .. '\n• '..config.cmd_pat .. plugin.command:gsub('%[', '\\[')
|
||||
end
|
||||
@ -21,17 +26,9 @@ function help:init(config)
|
||||
|
||||
table.insert(commandlist, 'hilfe [Plugin]')
|
||||
table.sort(commandlist)
|
||||
|
||||
help_text = help_text .. table.concat(commandlist, '\n• '..config.cmd_pat) .. '\nParameter: <benötigt> [optional]'
|
||||
|
||||
help_text = help_text:gsub('%[', '\\[')
|
||||
|
||||
help.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('hilfe', true):t('help', true).table
|
||||
|
||||
end
|
||||
|
||||
function help:action(msg)
|
||||
|
||||
local input = utilities.input(msg.text_lower)
|
||||
|
||||
-- Attempts to send the help message via PM.
|
130
miku/plugins/id.lua
Normal file
130
miku/plugins/id.lua
Normal file
@ -0,0 +1,130 @@
|
||||
local id = {}
|
||||
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
id.command = 'id'
|
||||
|
||||
function id:init(config)
|
||||
id.triggers = {
|
||||
"^/id$",
|
||||
"^/ids? (chat)$"
|
||||
}
|
||||
id.doc = [[```
|
||||
Returns user and chat info for you or the replied-to message.
|
||||
Alias: ]]..config.cmd_pat..[[who
|
||||
```]]
|
||||
end
|
||||
|
||||
function id:get_member_count(self, msg, chat_id)
|
||||
return bindings.request(self, 'getChatMembersCount', {
|
||||
chat_id = chat_id
|
||||
} )
|
||||
end
|
||||
|
||||
function id:user_print_name(user) -- Yes, copied from stats plugin
|
||||
if user.name then
|
||||
return user.name
|
||||
end
|
||||
|
||||
local text = ''
|
||||
if user.first_name then
|
||||
text = user.last_name..' '
|
||||
end
|
||||
if user.lastname then
|
||||
text = text..user.last_name
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function id:get_user(user_id, chat_id)
|
||||
local user_info = {}
|
||||
local uhash = 'user:'..user_id
|
||||
local user = redis:hgetall(uhash)
|
||||
user_info.name = id:user_print_name(user)
|
||||
user_info.id = user_id
|
||||
return user_info
|
||||
end
|
||||
|
||||
function id:action(msg)
|
||||
|
||||
if matches[1] == "/id" then
|
||||
if msg.reply_to_message then
|
||||
msg = msg.reply_to_message
|
||||
msg.from.name = utilities.build_name(msg.from.first_name, msg.from.last_name)
|
||||
end
|
||||
|
||||
local chat_id = msg.chat.id
|
||||
local user = 'Du bist @%s, auch bekannt als *%s* `[%s]`'
|
||||
if msg.from.username then
|
||||
user = user:format(utilities.markdown_escape(msg.from.username), msg.from.name, msg.from.id)
|
||||
else
|
||||
user = 'Du bist *%s* `[%s]`,'
|
||||
user = user:format(msg.from.name, msg.from.id)
|
||||
end
|
||||
|
||||
local group = '@%s, auch bekannt als *%s* `[%s]`.'
|
||||
if msg.chat.type == 'private' then
|
||||
group = group:format(utilities.markdown_escape(self.info.username), self.info.first_name, self.info.id)
|
||||
elseif msg.chat.username then
|
||||
group = group:format(utilities.markdown_escape(msg.chat.username), msg.chat.title, chat_id)
|
||||
else
|
||||
group = '*%s* `[%s]`.'
|
||||
group = group:format(msg.chat.title, chat_id)
|
||||
end
|
||||
|
||||
local output = user .. ', und du bist in der Gruppe ' .. group
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, msg.message_id, true)
|
||||
elseif matches[1] == "chat" then
|
||||
if msg.chat.type ~= 'group' and msg.chat.type ~= 'supergroup' then
|
||||
utilities.send_reply(self, msg, 'Das hier ist keine Gruppe!')
|
||||
return
|
||||
end
|
||||
local chat_name = msg.chat.title
|
||||
local chat_id = msg.chat.id
|
||||
-- Users on chat
|
||||
local hash = 'chat:'..chat_id..':users'
|
||||
local users = redis:smembers(hash)
|
||||
local users_info = {}
|
||||
-- Get user info
|
||||
for i = 1, #users do
|
||||
local user_id = users[i]
|
||||
local user_info = id:get_user(user_id, chat_id)
|
||||
table.insert(users_info, user_info)
|
||||
end
|
||||
|
||||
-- get all administrators and the creator
|
||||
local administrators = utilities.get_chat_administrators(self, chat_id)
|
||||
local admins = {}
|
||||
for num in pairs(administrators.result) do
|
||||
if administrators.result[num].status ~= 'creator' then
|
||||
table.insert(admins, tostring(administrators.result[num].user.id))
|
||||
else
|
||||
creator_id = administrators.result[num].user.id
|
||||
end
|
||||
end
|
||||
local result = id:get_member_count(self, msg, chat_id)
|
||||
local member_count = result.result - 1 -- minus the bot
|
||||
if member_count == 1 then
|
||||
member_count = 'ist *1 Mitglied'
|
||||
else
|
||||
member_count = 'sind *'..member_count..' Mitglieder'
|
||||
end
|
||||
local text = 'IDs für *'..chat_name..'* `['..chat_id..']`\nHier '..member_count..':*\n---------\n'
|
||||
for k,user in pairs(users_info) do
|
||||
if table.contains(admins, tostring(user.id)) then
|
||||
text = text..'*'..user.name..'* `['..user.id..']` _Administrator_\n'
|
||||
elseif tostring(creator_id) == user.id then
|
||||
text = text..'*'..user.name..'* `['..user.id..']` _Gruppenersteller_\n'
|
||||
else
|
||||
text = text..'*'..user.name..'* `['..user.id..']`\n'
|
||||
end
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
end
|
||||
|
||||
return id
|
80
miku/plugins/ifttt.lua
Normal file
80
miku/plugins/ifttt.lua
Normal file
@ -0,0 +1,80 @@
|
||||
local ifttt = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function ifttt:init(config)
|
||||
ifttt.triggers = {
|
||||
"^/ifttt (!set) (.*)$",
|
||||
"^/ifttt (!unauth)$",
|
||||
"^/ifttt (.*)%&(.*)%&(.*)%&(.*)",
|
||||
"^/ifttt (.*)%&(.*)%&(.*)",
|
||||
"^/ifttt (.*)%&(.*)",
|
||||
"^/ifttt (.*)$"
|
||||
}
|
||||
|
||||
ifttt.doc = [[*
|
||||
]]..config.cmd_pat..[[ifttt* _!set_ _<Key>_: Speichere deinen Schlüssel ein (erforderlich)
|
||||
*]]..config.cmd_pat..[[ifttt* _!unauth_: Löscht deinen Account aus dem Bot
|
||||
*]]..config.cmd_pat..[[ifttt* _<Event>_&_<Value1>_&_<Value2>_&_<Value3>_: Führt [Event] mit den optionalen Parametern Value1, Value2 und Value3 aus
|
||||
Beispiel: `/ifttt DeinFestgelegterName&Hallo&NochEinHallo`: Führt 'DeinFestgelegterName' mit den Parametern 'Hallo' und 'NochEinHallo' aus.]]
|
||||
end
|
||||
|
||||
ifttt.command = 'ifttt <Event>&<Value1>&<Value2>&<Value3>'
|
||||
|
||||
local BASE_URL = 'https://maker.ifttt.com/trigger'
|
||||
|
||||
function ifttt:set_ifttt_key(hash, key)
|
||||
print('Setting ifttt in redis hash '..hash..' to '..key)
|
||||
redis:hset(hash, 'ifttt', key)
|
||||
return '*Schlüssel eingespeichert!* Das Plugin kann jetzt verwendet werden.'
|
||||
end
|
||||
|
||||
function ifttt:do_ifttt_request(key, event, value1, value2, value3)
|
||||
if not value1 then
|
||||
url = BASE_URL..'/'..event..'/with/key/'..key
|
||||
elseif not value2 then
|
||||
url = BASE_URL..'/'..event..'/with/key/'..key..'/?value1='..URL.escape(value1)
|
||||
elseif not value3 then
|
||||
url = BASE_URL..'/'..event..'/with/key/'..key..'/?value1='..URL.escape(value1)..'&value2='..URL.escape(value2)
|
||||
else
|
||||
url = BASE_URL..'/'..event..'/with/key/'..key..'/?value1='..URL.escape(value1)..'&value2='..URL.escape(value2)..'&value3='..URL.escape(value3)
|
||||
end
|
||||
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "*Ein Fehler ist aufgetreten!* Aktion wurde nicht ausgeführt." end
|
||||
|
||||
return "*Event \""..event.."\" getriggert!*"
|
||||
end
|
||||
|
||||
function ifttt:action(msg, config, matches)
|
||||
local hash = 'user:'..msg.from.id
|
||||
local key = redis:hget(hash, 'ifttt')
|
||||
local event = matches[1]
|
||||
local value1 = matches[2]
|
||||
local value2 = matches[3]
|
||||
local value3 = matches[4]
|
||||
|
||||
if event == '!set' then
|
||||
utilities.send_reply(self, msg, ifttt:set_ifttt_key(hash, value1), true)
|
||||
return
|
||||
end
|
||||
|
||||
if not key then
|
||||
utilities.send_reply(self, msg, '*Bitte speichere zuerst deinen Schlüssel ein!* Aktiviere dazu den [Maker Channel](https://ifttt.com/maker) und speichere deinen Schlüssel mit `/ifttt !set KEY` ein', true)
|
||||
return
|
||||
end
|
||||
|
||||
if event == '!unauth' then
|
||||
redis:hdel(hash, 'ifttt')
|
||||
utilities.send_reply(self, msg, '*Erfolgreich ausgeloggt!*', true)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg, ifttt:do_ifttt_request(key, event, value1, value2, value3), true)
|
||||
end
|
||||
|
||||
return ifttt
|
21
miku/plugins/images.lua
Normal file
21
miku/plugins/images.lua
Normal file
@ -0,0 +1,21 @@
|
||||
local images = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
images.triggers = {
|
||||
"(https?://[%w-_%%%.%?%.:,/%+=~&%[%]]+%.[Pp][Nn][Gg])$",
|
||||
"(https?://[%w-_%%%.%?%.:,/%+=~&%[%]]+%.[Jj][Pp][Ee]?[Gg])$"
|
||||
}
|
||||
|
||||
function images:action(msg)
|
||||
local url = matches[1]
|
||||
local file, last_modified, nocache = get_cached_file(url, nil, msg.chat.id, 'upload_photo', self)
|
||||
local result = utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
|
||||
if nocache then return end
|
||||
if not result then return end
|
||||
|
||||
-- Cache File-ID und Last-Modified-Header in Redis
|
||||
cache_file(result, url, last_modified)
|
||||
end
|
||||
|
||||
return images
|
@ -3,8 +3,8 @@ local imdb = {}
|
||||
local HTTP = require('socket.http')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
imdb.command = 'imdb <query>'
|
||||
|
@ -1,12 +1,16 @@
|
||||
local imgblacklist = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
imgblacklist.command = 'imgblacklist'
|
||||
|
||||
function imgblacklist:init(config)
|
||||
imgblacklist.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('imgblacklist', true).table
|
||||
imgblacklist.triggers = {
|
||||
"^/imgblacklist show$",
|
||||
"^/imgblacklist (add) (.*)$",
|
||||
"^/imgblacklist (remove) (.*)$"
|
||||
}
|
||||
imgblacklist.doc = [[*
|
||||
]]..config.cmd_pat..[[imgblacklist* _show_: Zeige Blacklist
|
||||
*]]..config.cmd_pat..[[imgblacklist* _add_ _<Wort>_: Fügt Wort der Blacklist hinzu
|
||||
@ -47,30 +51,34 @@ function imgblacklist:remove_blacklist(word)
|
||||
end
|
||||
end
|
||||
|
||||
function imgblacklist:action(msg)
|
||||
function imgblacklist:action(msg, config, matches)
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
local input = string.lower(input)
|
||||
|
||||
local action = matches[1]
|
||||
if matches[2] then word = string.lower(matches[2]) else word = nil end
|
||||
_blacklist = redis:smembers("telegram:img_blacklist")
|
||||
|
||||
if input:match('(add) (.*)') then
|
||||
local word = input:match('add (.*)')
|
||||
output = imgblacklist:add_blacklist(word)
|
||||
elseif input:match('(remove) (.*)') then
|
||||
local word = input:match('remove (.*)')
|
||||
output = imgblacklist:remove_blacklist(word)
|
||||
elseif input:match('(show)') then
|
||||
output = imgblacklist:show_blacklist()
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, imgblacklist.doc, true, msg.message_id, true)
|
||||
if action == 'add' and not word then
|
||||
utilities.send_reply(self, msg, imgblacklist.doc, true)
|
||||
return
|
||||
elseif action == "add" and word then
|
||||
utilities.send_reply(self, msg, imgblacklist:add_blacklist(word), true)
|
||||
return
|
||||
end
|
||||
|
||||
if action == 'remove' and not word then
|
||||
utilities.send_reply(self, msg, imgblacklist.doc, true)
|
||||
return
|
||||
elseif action == "remove" and word then
|
||||
utilities.send_reply(self, msg, imgblacklist:remove_blacklist(word), true)
|
||||
return
|
||||
end
|
||||
|
||||
utilities.send_message(self, msg.chat.id, output, true, nil, true)
|
||||
utilities.send_reply(self, msg, imgblacklist:show_blacklist())
|
||||
end
|
||||
|
||||
return imgblacklist
|
60
miku/plugins/imgur.lua
Normal file
60
miku/plugins/imgur.lua
Normal file
@ -0,0 +1,60 @@
|
||||
local imgur = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function imgur:init(config)
|
||||
if not cred_data.imgur_client_id then
|
||||
print('Missing config value: imgur_client_id.')
|
||||
print('imgur.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
imgur.triggers = {
|
||||
"imgur.com/([A-Za-z0-9]+).gifv",
|
||||
"https?://imgur.com/([A-Za-z0-9]+)"
|
||||
}
|
||||
end
|
||||
|
||||
local client_id = cred_data.imgur_client_id
|
||||
local BASE_URL = 'https://api.imgur.com/3'
|
||||
|
||||
function imgur:get_imgur_data(imgur_code)
|
||||
local response_body = {}
|
||||
local request_constructor = {
|
||||
url = BASE_URL..'/image/'..imgur_code,
|
||||
method = "GET",
|
||||
sink = ltn12.sink.table(response_body),
|
||||
headers = {
|
||||
Authorization = 'Client-ID '..client_id
|
||||
}
|
||||
}
|
||||
local ok, response_code, response_headers, response_status_line = https.request(request_constructor)
|
||||
if not ok then
|
||||
return nil
|
||||
end
|
||||
|
||||
local response_body = json.decode(table.concat(response_body))
|
||||
|
||||
if response_body.status ~= 200 then return nil end
|
||||
|
||||
return response_body.data.link
|
||||
end
|
||||
|
||||
function imgur:action(msg)
|
||||
local imgur_code = matches[1]
|
||||
if imgur_code == "login" then return nil end
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local link = imgur:get_imgur_data(imgur_code)
|
||||
if link then
|
||||
local file = download_to_file(link)
|
||||
if string.ends(link, ".gif") then
|
||||
utilities.send_document(self, msg.chat.id, file, nil, msg.message_id)
|
||||
else
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return imgur
|
80
miku/plugins/instagram.lua
Normal file
80
miku/plugins/instagram.lua
Normal file
@ -0,0 +1,80 @@
|
||||
local instagram = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function instagram:init(config)
|
||||
if not cred_data.instagram_access_token then
|
||||
print('Missing config value: instagram_access_token.')
|
||||
print('instagram.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
instagram.triggers = {
|
||||
"instagram.com/p/([A-Za-z0-9-_-]+)"
|
||||
}
|
||||
end
|
||||
|
||||
local BASE_URL = 'https://api.instagram.com/v1'
|
||||
local access_token = cred_data.instagram_access_token
|
||||
|
||||
function instagram:get_insta_data(insta_code)
|
||||
local url = BASE_URL..'/media/shortcode/'..insta_code..'?access_token='..access_token
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res).data
|
||||
return data
|
||||
end
|
||||
|
||||
function instagram:send_instagram_data(data)
|
||||
-- Header
|
||||
local username = data.user.username
|
||||
local full_name = data.user.full_name
|
||||
if username == full_name then
|
||||
header = full_name..' hat ein'
|
||||
else
|
||||
header = full_name..' ('..username..') hat ein'
|
||||
end
|
||||
if data.type == 'video' then
|
||||
header = header..' Video gepostet'
|
||||
else
|
||||
header = header..' Foto gepostet'
|
||||
end
|
||||
|
||||
-- Caption
|
||||
if data.caption == nil then
|
||||
caption = ''
|
||||
else
|
||||
caption = ':\n'..data.caption.text
|
||||
end
|
||||
|
||||
-- Footer
|
||||
local comments = comma_value(data.comments.count)
|
||||
local likes = comma_value(data.likes.count)
|
||||
local footer = '\n'..likes..' Likes, '..comments..' Kommentare'
|
||||
if data.type == 'video' then
|
||||
footer = '\n'..data.videos.standard_resolution.url..footer
|
||||
end
|
||||
|
||||
-- Image
|
||||
local image_url = data.images.standard_resolution.url
|
||||
|
||||
return header..caption..footer, image_url
|
||||
end
|
||||
|
||||
function instagram:action(msg, config, matches)
|
||||
local insta_code = matches[1]
|
||||
local data = instagram:get_insta_data(insta_code)
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
local text, image_url = instagram:send_instagram_data(data)
|
||||
if not image_url then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
end
|
||||
|
||||
return instagram
|
92
miku/plugins/ip_info.lua
Normal file
92
miku/plugins/ip_info.lua
Normal file
@ -0,0 +1,92 @@
|
||||
local ip_info = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local json = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function ip_info:init(config)
|
||||
ip_info.triggers = {
|
||||
"^/ip (.*)$",
|
||||
"^/dns (.*)$"
|
||||
}
|
||||
|
||||
ip_info.doc = [[*
|
||||
]]..config.cmd_pat..[[ip* _<IP-Adresse>_: Sendet Infos zu dieser IP]]
|
||||
end
|
||||
|
||||
ip_info.command = 'ip <IP-Adresse>'
|
||||
|
||||
local BASE_URL = 'http://ip-api.com/json'
|
||||
|
||||
function ip_info:get_host_data(host)
|
||||
local url = BASE_URL..'/'..host..'?lang=de&fields=country,regionName,city,zip,lat,lon,isp,org,as,status,message,reverse,query'
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER: "..code end
|
||||
local data = json.decode(res)
|
||||
if data.status == 'fail' then
|
||||
return nil
|
||||
end
|
||||
|
||||
local isp = data.isp
|
||||
|
||||
local url
|
||||
if data.lat and data.lon then
|
||||
lat = tostring(data.lat)
|
||||
lon = tostring(data.lon)
|
||||
url = "https://maps.googleapis.com/maps/api/staticmap?zoom=16&size=600x300&maptype=hybrid¢er="..lat..","..lon.."&markers=color:red%7Clabel:•%7C"..lat..","..lon
|
||||
end
|
||||
|
||||
if data.query == host then
|
||||
query = ''
|
||||
else
|
||||
query = ' / '..data.query
|
||||
end
|
||||
|
||||
if data.reverse ~= "" and data.reverse ~= host then
|
||||
host_addr = ' ('..data.reverse..')'
|
||||
else
|
||||
host_addr = ''
|
||||
end
|
||||
|
||||
-- Location
|
||||
if data.zip ~= "" then
|
||||
zipcode = data.zip..' '
|
||||
else
|
||||
zipcode = ''
|
||||
end
|
||||
|
||||
local city = data.city
|
||||
|
||||
if data.regionName ~= "" then
|
||||
region = ', '..data.regionName
|
||||
else
|
||||
region = ''
|
||||
end
|
||||
|
||||
if data.country ~= "" then
|
||||
country = ', '..data.country
|
||||
else
|
||||
country = ''
|
||||
end
|
||||
|
||||
local text = host..query..host_addr..' ist bei '..isp..':\n'
|
||||
local location = zipcode..city..region..country
|
||||
return text..location, url
|
||||
end
|
||||
|
||||
function ip_info:action(msg, config, matches)
|
||||
local host = matches[1]
|
||||
local text, image_url = ip_info:get_host_data(host)
|
||||
if not text then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url, 'map.png')
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id)
|
||||
else
|
||||
utilities.send_reply(self, msg, text)
|
||||
end
|
||||
end
|
||||
|
||||
return ip_info
|
85
miku/plugins/isup.lua
Normal file
85
miku/plugins/isup.lua
Normal file
@ -0,0 +1,85 @@
|
||||
local isup = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local socket = require('socket')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function isup:init(config)
|
||||
isup.triggers = {
|
||||
"^/isup (.*)$",
|
||||
"^/ping (.*)$"
|
||||
}
|
||||
|
||||
isup.doc = [[*
|
||||
]]..config.cmd_pat..[[isup* _<URL>_: Prüft, ob die URL up ist]]
|
||||
end
|
||||
|
||||
function isup:is_up_socket(ip, port)
|
||||
print('Connect to', ip, port)
|
||||
local c = socket.try(socket.tcp())
|
||||
c:settimeout(3)
|
||||
local conn = c:connect(ip, port)
|
||||
if not conn then
|
||||
return false
|
||||
else
|
||||
c:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function isup:is_up_http(url)
|
||||
-- Parse URL from input, default to http
|
||||
local parsed_url = URL.parse(url, { scheme = 'http', authority = '' })
|
||||
-- Fix URLs without subdomain not parsed properly
|
||||
if not parsed_url.host and parsed_url.path then
|
||||
parsed_url.host = parsed_url.path
|
||||
parsed_url.path = ""
|
||||
end
|
||||
-- Re-build URL
|
||||
local url = URL.build(parsed_url)
|
||||
|
||||
local protocols = {
|
||||
["https"] = https,
|
||||
["http"] = http
|
||||
}
|
||||
local options = {
|
||||
url = url,
|
||||
redirect = false,
|
||||
method = "GET"
|
||||
}
|
||||
local response = { protocols[parsed_url.scheme].request(options) }
|
||||
local code = tonumber(response[2])
|
||||
if code == nil or code >= 400 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function isup:isup(url)
|
||||
local pattern = '^(%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?):?(%d?%d?%d?%d?%d?)$'
|
||||
local ip,port = string.match(url, pattern)
|
||||
local result = nil
|
||||
|
||||
-- /isup 8.8.8.8:53
|
||||
if ip then
|
||||
port = port or '80'
|
||||
result = isup:is_up_socket(ip, port)
|
||||
else
|
||||
result = isup:is_up_http(url)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function isup:action(msg, config)
|
||||
if isup:isup(matches[1]) then
|
||||
utilities.send_reply(self, msg, matches[1]..' ist UP! ✅')
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, matches[1]..' ist DOWN! ❌')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return isup
|
52
miku/plugins/leave_group.lua
Normal file
52
miku/plugins/leave_group.lua
Normal file
@ -0,0 +1,52 @@
|
||||
local leave_group = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
leave_group.triggers = {
|
||||
'/nil'
|
||||
}
|
||||
|
||||
local report_to_admin = true -- set to false to not be notified, when Bot leaves groups without you
|
||||
|
||||
function leave_group:check_for_admin(msg, self, config)
|
||||
local result = bindings.request(self, 'getChatMember', {
|
||||
chat_id = msg.chat.id,
|
||||
user_id = config.admin
|
||||
} )
|
||||
if not result.ok then
|
||||
print('Konnte nicht prüfen, ob Admin in Gruppe ist! Verlasse sie sicherheitshalber...')
|
||||
return false
|
||||
end
|
||||
if result.result.status ~= "member" and result.result.status ~= "administrator" and result.result.status ~= "creator" then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function leave_group:pre_process(msg, self, config)
|
||||
if msg.group_chat_created or msg.new_chat_member then
|
||||
local admin_in_group = leave_group:check_for_admin(msg, self, config)
|
||||
if not admin_in_group then
|
||||
print('Admin ist nicht in der Gruppe, verlasse sie deshalb...')
|
||||
utilities.send_reply(self, msg, 'Dieser Bot wurde in eine fremde Gruppe hinzugefügt. Dies wird gemeldet!\nThis bot was added to foreign group. This incident will be reported!')
|
||||
local result = bindings.request(self, 'leaveChat', {
|
||||
chat_id = msg.chat.id
|
||||
} )
|
||||
local chat_name = msg.chat.title
|
||||
local chat_id = msg.chat.id
|
||||
local from = msg.from.name
|
||||
local from_id = msg.from.id
|
||||
if report_to_admin then
|
||||
utilities.send_message(self, config.admin, '#WARNUNG: Bot wurde in fremde Gruppe hinzugefügt:\nGruppenname: '..chat_name..' ('..chat_id..')\nHinzugefügt von: '..from..' ('..from_id..')')
|
||||
end
|
||||
end
|
||||
end
|
||||
return msg
|
||||
end
|
||||
|
||||
function leave_group:action(msg)
|
||||
end
|
||||
|
||||
return leave_group
|
@ -1,7 +1,7 @@
|
||||
local loc_manager = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function loc_manager:init(config)
|
||||
loc_manager.triggers = {
|
@ -1,6 +1,6 @@
|
||||
local luarun = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
|
||||
@ -25,9 +25,9 @@ function luarun:action(msg, config)
|
||||
end
|
||||
|
||||
local output = loadstring( [[
|
||||
local bot = require('otouto.bot')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bot = require('miku.bot')
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local JSON = require('dkjson')
|
||||
local URL = require('socket.url')
|
||||
local HTTP = require('socket.http')
|
51
miku/plugins/lyrics.lua
Normal file
51
miku/plugins/lyrics.lua
Normal file
@ -0,0 +1,51 @@
|
||||
local lyrics = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function lyrics:init(config)
|
||||
if not cred_data.lyricsnmusic_apikey then
|
||||
print('Missing config value: lyricsnmusic_apikey.')
|
||||
print('lyrics.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
lyrics.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('lyrics', true).table
|
||||
lyrics.doc = [[*
|
||||
]]..config.cmd_pat..[[lyrics* _<Lied>_: Postet Liedertext]]
|
||||
end
|
||||
|
||||
lyrics.command = 'lyrics <Lied>'
|
||||
|
||||
function lyrics:getLyrics(text)
|
||||
local apikey = cred_data.lyricsnmusic_apikey
|
||||
local q = url_encode(text)
|
||||
local b = http.request("http://api.lyricsnmusic.com/songs?api_key="..apikey.."&q=" .. q)
|
||||
response = json.decode(b)
|
||||
local reply = ""
|
||||
if #response > 0 then
|
||||
-- grab first match
|
||||
local result = response[1]
|
||||
reply = result.title .. " - " .. result.artist.name .. "\n" .. result.snippet .. "\n[Ganzen Liedertext ansehen](" .. result.url .. ")"
|
||||
else
|
||||
reply = nil
|
||||
end
|
||||
return reply
|
||||
end
|
||||
|
||||
function lyrics:action(msg, config, matches)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, lyrics.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
utilities.send_reply(self, msg, lyrics:getLyrics(input), true)
|
||||
end
|
||||
|
||||
return lyrics
|
23
miku/plugins/magische_miesmuschel.lua
Normal file
23
miku/plugins/magische_miesmuschel.lua
Normal file
@ -0,0 +1,23 @@
|
||||
local muschel = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
muschel.triggers = {
|
||||
"^[Mm][Aa][Gg][Ii][Ss][Cc][Hh][Ee] [Mm][Ii][Ee][Ss][Mm][Uu][Ss][Cc][Hh][Ee][Ll], (.*)$"
|
||||
}
|
||||
|
||||
function muschel:frag_die_muschel()
|
||||
local possibilities = {
|
||||
"Ja",
|
||||
"Nein",
|
||||
"Eines Tages vielleicht"
|
||||
}
|
||||
local random = math.random(3)
|
||||
return possibilities[random]
|
||||
end
|
||||
|
||||
function muschel:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, muschel:frag_die_muschel())
|
||||
end
|
||||
|
||||
return muschel
|
@ -1,7 +1,10 @@
|
||||
local media = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local mimetype = (loadfile "./otouto/mimetype.lua")()
|
||||
local HTTP = require('socket.http')
|
||||
local HTTPS = require('ssl.https')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local mimetype = (loadfile "./miku/mimetype.lua")()
|
||||
|
||||
media.triggers = {
|
||||
"(https?://[%w-_%.%?%.:,/%+=&%[%]]+%.(gif))$",
|
||||
@ -28,40 +31,28 @@ function media:action(msg)
|
||||
local ext = matches[2]
|
||||
local receiver = msg.chat.id
|
||||
|
||||
utilities.send_typing(self, receiver, 'upload_document')
|
||||
local file = download_to_file(url)
|
||||
local file, last_modified, nocache = get_cached_file(url, nil, msg.chat.id, 'upload_document', self)
|
||||
local mime_type = mimetype.get_content_type_no_sub(ext)
|
||||
|
||||
if ext == 'gif' then
|
||||
print('send gif')
|
||||
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
|
||||
elseif mime_type == 'text' then
|
||||
print('send_document')
|
||||
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
|
||||
elseif mime_type == 'image' then
|
||||
print('send_photo')
|
||||
utilities.send_photo(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
|
||||
result = utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||
elseif mime_type == 'audio' then
|
||||
print('send_audio')
|
||||
utilities.send_audio(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
|
||||
result = utilities.send_audio(self, receiver, file, nil, msg.message_id)
|
||||
elseif mime_type == 'video' then
|
||||
print('send_video')
|
||||
utilities.send_video(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
|
||||
result = utilities.send_video(self, receiver, file, nil, msg.message_id)
|
||||
else
|
||||
print('send_file')
|
||||
utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||
return
|
||||
result = utilities.send_document(self, receiver, file, nil, msg.message_id)
|
||||
end
|
||||
|
||||
if nocache then return end
|
||||
if not result then return end
|
||||
|
||||
-- Cache File-ID und Last-Modified-Header in Redis
|
||||
cache_file(result, url, last_modified)
|
||||
end
|
||||
|
||||
return media
|
86
miku/plugins/minecraft_server.lua
Normal file
86
miku/plugins/minecraft_server.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local mc_server = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local ltn12 = require('ltn12')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function mc_server:init(config)
|
||||
mc_server.triggers = {
|
||||
"^/mine (.*)$"
|
||||
}
|
||||
mc_server.doc = [[*
|
||||
]]..config.cmd_pat..[[mine* _<IP>_: Sucht Minecraft-Server und sendet Infos. Standard-Port: 25565
|
||||
*]]..config.cmd_pat..[[mine* _<IP>_ _<Port>_: Sucht Minecraft-Server auf Port und sendet Infos.
|
||||
]]
|
||||
end
|
||||
|
||||
mc_server.command = "mine <IP> [Port]"
|
||||
|
||||
function mc_server:mineSearch(ip, port)
|
||||
local responseText = ""
|
||||
local api = "https://mcapi.us/server/status"
|
||||
local parameters = "?ip="..(URL.escape(ip) or "").."&port="..(URL.escape(port) or "").."&players=true"
|
||||
local respbody = {}
|
||||
local body, code, headers, status = http.request{
|
||||
url = api..parameters,
|
||||
method = "GET",
|
||||
redirect = true,
|
||||
sink = ltn12.sink.table(respbody)
|
||||
}
|
||||
local body = table.concat(respbody)
|
||||
if (status == nil) then return "FEHLER: status = nil" end
|
||||
if code ~=200 then return "FEHLER: "..code..". Status: "..status end
|
||||
local jsonData = json.decode(body)
|
||||
responseText = responseText..ip..":"..port..":\n"
|
||||
if (jsonData.motd ~= nil and jsonData.motd ~= '') then
|
||||
local tempMotd = ""
|
||||
tempMotd = jsonData.motd:gsub('%ยง.', '')
|
||||
if (jsonData.motd ~= nil) then responseText = responseText.."*MOTD*: "..tempMotd.."\n" end
|
||||
end
|
||||
if (jsonData.online ~= nil) then
|
||||
if jsonData.online == true then
|
||||
server_online = "Ja"
|
||||
else
|
||||
server_online = "Nein"
|
||||
end
|
||||
responseText = responseText.."*Online*: "..server_online.."\n"
|
||||
end
|
||||
if (jsonData.players ~= nil) then
|
||||
if (jsonData.players.max ~= nil and jsonData.players.max ~= 0) then
|
||||
responseText = responseText.."*Slots*: "..jsonData.players.max.."\n"
|
||||
end
|
||||
if (jsonData.players.now ~= nil and jsonData.players.max ~= 0) then
|
||||
responseText = responseText.."*Spieler online*: "..jsonData.players.now.."\n"
|
||||
end
|
||||
if (jsonData.players.sample ~= nil and jsonData.players.sample ~= false) then
|
||||
responseText = responseText.."*Spieler*: "..table.concat(jsonData.players.sample, ", ").."\n"
|
||||
end
|
||||
if (jsonData.server.name ~= nil and jsonData.server.name ~= "") then
|
||||
responseText = responseText.."*Server*: "..jsonData.server.name.."\n"
|
||||
end
|
||||
end
|
||||
return responseText
|
||||
end
|
||||
|
||||
function mc_server:parseText(text, mc_server)
|
||||
if (text == nil or text == "/mine") then
|
||||
return mc_server.doc
|
||||
end
|
||||
ip, port = string.match(text, "^/mine (.-) (.*)$")
|
||||
if (ip ~= nil and port ~= nil) then
|
||||
return mc_server:mineSearch(ip, port)
|
||||
end
|
||||
local ip = string.match(text, "^/mine (.*)$")
|
||||
if (ip ~= nil) then
|
||||
return mc_server:mineSearch(ip, "25565")
|
||||
end
|
||||
return "FEHLER: Keine Input IP!"
|
||||
end
|
||||
|
||||
function mc_server:action(msg, config, matches)
|
||||
utilities.send_reply(self, msg, mc_server:parseText(msg.text, mc_server), true)
|
||||
end
|
||||
|
||||
return mc_server
|
31
miku/plugins/minecraft_skin.lua
Normal file
31
miku/plugins/minecraft_skin.lua
Normal file
@ -0,0 +1,31 @@
|
||||
local mc_skin = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function mc_skin:init(config)
|
||||
mc_skin.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('skin', true).table
|
||||
mc_skin.doc = [[*
|
||||
]]..config.cmd_pat..[[skin* _<Username>_: Sendet Minecraft-Skin dieses Nutzers]]
|
||||
end
|
||||
|
||||
mc_skin.command = 'skin <Username>'
|
||||
|
||||
local BASE_URL = 'http://ip-api.com/json'
|
||||
|
||||
function mc_skin:action(msg, config, matches)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, mc_skin.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local url = 'http://www.minecraft-skin-viewer.net/3d.php?layers=true&aa=true&a=0&w=330&wt=10&abg=330&abd=40&ajg=340&ajd=20&ratio=13&format=png&login='..input..'&headOnly=false&displayHairs=true&randomness=341.png'
|
||||
local file = download_to_file(url)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
|
||||
return mc_skin
|
228
miku/plugins/myanimelist.lua
Normal file
228
miku/plugins/myanimelist.lua
Normal file
@ -0,0 +1,228 @@
|
||||
local mal = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local URL = require('socket.url')
|
||||
local xml = require("xml")
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
mal.command = 'anime <Anime>, /manga <Manga>'
|
||||
|
||||
function mal:init(config)
|
||||
if not cred_data.mal_user then
|
||||
print('Missing config value: mal_user.')
|
||||
print('myanimelist.lua will not be enabled.')
|
||||
return
|
||||
elseif not cred_data.mal_pw then
|
||||
print('Missing config value: mal_pw.')
|
||||
print('myanimelist.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
mal.triggers = {
|
||||
"^/(anime) (.+)$",
|
||||
"^/(manga) (.+)$"
|
||||
}
|
||||
mal.doc = [[*
|
||||
]]..config.cmd_pat..[[anime*_ <Anime>_: Sendet Infos zum Anime
|
||||
*]]..config.cmd_pat..[[manga*_ <Manga>_: Sendet Infos zum Manga
|
||||
]]
|
||||
end
|
||||
|
||||
local user = cred_data.mal_user
|
||||
local password = cred_data.mal_pw
|
||||
|
||||
local BASE_URL = 'http://'..user..':'..password..'@myanimelist.net/api'
|
||||
|
||||
function mal:delete_tags(str)
|
||||
str = string.gsub( str, '<br />', '')
|
||||
str = string.gsub( str, '%[i%]', '')
|
||||
str = string.gsub( str, '%[/i%]', '')
|
||||
str = string.gsub( str, '—', ' — ')
|
||||
return str
|
||||
end
|
||||
|
||||
local makeOurDate = function(dateString)
|
||||
local pattern = "(%d+)%-(%d+)%-(%d+)"
|
||||
local year, month, day = dateString:match(pattern)
|
||||
return day..'.'..month..'.'..year
|
||||
end
|
||||
|
||||
function mal:get_mal_info(query, typ)
|
||||
if typ == 'anime' then
|
||||
url = BASE_URL..'/anime/search.xml?q='..query
|
||||
elseif typ == 'manga' then
|
||||
url = BASE_URL..'/manga/search.xml?q='..query
|
||||
end
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return "HTTP-Fehler" end
|
||||
local result = xml.load(res)
|
||||
return result
|
||||
end
|
||||
|
||||
function mal:send_anime_data(result, receiver)
|
||||
local title = xml.find(result, 'title')[1]
|
||||
local id = xml.find(result, 'id')[1]
|
||||
local mal_url = 'http://myanimelist.net/anime/'..id
|
||||
|
||||
if xml.find(result, 'synonyms')[1] then
|
||||
alt_name = '\noder: '..unescape(mal:delete_tags(xml.find(result, 'synonyms')[1]))
|
||||
else
|
||||
alt_name = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'synopsis')[1] then
|
||||
desc = '\n'..unescape(mal:delete_tags(string.sub(xml.find(result, 'synopsis')[1], 1, 200))) .. '...'
|
||||
else
|
||||
desc = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'episodes')[1] then
|
||||
episodes = '\nEpisoden: '..xml.find(result, 'episodes')[1]
|
||||
else
|
||||
episodes = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'status')[1] then
|
||||
status = ' ('..xml.find(result, 'status')[1]..')'
|
||||
else
|
||||
status = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'score')[1] ~= "0.00" then
|
||||
score = '\nScore: '..string.gsub(xml.find(result, 'score')[1], "%.", ",")
|
||||
else
|
||||
score = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'type')[1] then
|
||||
typ = '\nTyp: '..xml.find(result, 'type')[1]
|
||||
else
|
||||
typ = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'start_date')[1] ~= "0000-00-00" then
|
||||
startdate = '\nVeröffentlichungszeitraum: '..makeOurDate(xml.find(result, 'start_date')[1])
|
||||
else
|
||||
startdate = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'end_date')[1] ~= "0000-00-00" then
|
||||
enddate = ' - '..makeOurDate(xml.find(result, 'end_date')[1])
|
||||
else
|
||||
enddate = ''
|
||||
end
|
||||
|
||||
local text = '*'..title..'*'..alt_name..typ..episodes..status..score..startdate..enddate..'_'..desc..'_\n[Auf MyAnimeList ansehen]('..mal_url..')'
|
||||
if xml.find(result, 'image') then
|
||||
local image_url = xml.find(result, 'image')[1]
|
||||
return text, image_url
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
function mal:send_manga_data(result)
|
||||
local title = xml.find(result, 'title')[1]
|
||||
local id = xml.find(result, 'id')[1]
|
||||
local mal_url = 'http://myanimelist.net/manga/'..id
|
||||
|
||||
if xml.find(result, 'type')[1] then
|
||||
typ = ' ('..xml.find(result, 'type')[1]..')'
|
||||
else
|
||||
typ = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'synonyms')[1] then
|
||||
alt_name = '\noder: '..unescape(mal:delete_tags(xml.find(result, 'synonyms')[1]))
|
||||
else
|
||||
alt_name = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'chapters')[1] then
|
||||
chapters = '\nKapitel: '..xml.find(result, 'chapters')[1]
|
||||
else
|
||||
chapters = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'status')[1] then
|
||||
status = ' ('..xml.find(result, 'status')[1]..')'
|
||||
else
|
||||
status = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'volumes')[1] then
|
||||
volumes = '\nBände '..xml.find(result, 'volumes')[1]
|
||||
else
|
||||
volumes = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'score')[1] ~= "0.00" then
|
||||
score = '\nScore: '..xml.find(result, 'score')[1]
|
||||
else
|
||||
score = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'start_date')[1] ~= "0000-00-00" then
|
||||
startdate = '\nVeröffentlichungszeitraum: '..makeOurDate(xml.find(result, 'start_date')[1])
|
||||
else
|
||||
startdate = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'end_date')[1] ~= "0000-00-00" then
|
||||
enddate = ' - '..makeOurDate(xml.find(result, 'end_date')[1])
|
||||
else
|
||||
enddate = ''
|
||||
end
|
||||
|
||||
if xml.find(result, 'synopsis')[1] then
|
||||
desc = '\n'..unescape(mal:delete_tags(string.sub(xml.find(result, 'synopsis')[1], 1, 200))) .. '...'
|
||||
else
|
||||
desc = ''
|
||||
end
|
||||
|
||||
local text = '*'..title..'*'..alt_name..typ..chapters..status..volumes..score..startdate..enddate..'_'..desc..'_\n[Auf MyAnimeList ansehen]('..mal_url..')'
|
||||
if xml.find(result, 'image') then
|
||||
local image_url = xml.find(result, 'image')[1]
|
||||
return text, image_url
|
||||
else
|
||||
return text
|
||||
end
|
||||
end
|
||||
|
||||
function mal:action(msg, config, matches)
|
||||
local query = URL.escape(matches[2])
|
||||
if matches[1] == 'anime' then
|
||||
local anime_info = mal:get_mal_info(query, 'anime')
|
||||
if anime_info == "HTTP-Fehler" then
|
||||
utilities.send_reply(self, msg, 'Anime nicht gefunden!')
|
||||
return
|
||||
else
|
||||
local text, image_url = mal:send_anime_data(anime_info)
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
return
|
||||
end
|
||||
elseif matches[1] == 'manga' then
|
||||
local manga_info = mal:get_mal_info(query, 'manga')
|
||||
if manga_info == "HTTP-Fehler" then
|
||||
utilities.send_reply(self, msg, 'Manga nicht gefunden!')
|
||||
return
|
||||
else
|
||||
local text, image_url = mal:send_manga_data(manga_info)
|
||||
if image_url then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(image_url)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return mal
|
103
miku/plugins/notify.lua
Normal file
103
miku/plugins/notify.lua
Normal file
@ -0,0 +1,103 @@
|
||||
-- INFO: Stats must be activated, so that it can collect all members of a group and save his/her id to redis.
|
||||
-- You can deactivate it afterwards.
|
||||
|
||||
local notify = {}
|
||||
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function notify:init(config)
|
||||
notify.triggers = {
|
||||
"^/notify (del)$",
|
||||
"^/notify$"
|
||||
}
|
||||
|
||||
notify.doc = [[*
|
||||
]]..config.cmd_pat..[[notify* (del): Benachrichtigt dich privat, wenn du erwähnt wirst (bzw. schaltet das Feature wieder aus)]]
|
||||
end
|
||||
|
||||
notify.command = 'notify [del]'
|
||||
|
||||
-- See https://stackoverflow.com/a/32854917
|
||||
function isWordFoundInString(word,input)
|
||||
return select(2,input:gsub('^' .. word .. '%W+','')) +
|
||||
select(2,input:gsub('%W+' .. word .. '$','')) +
|
||||
select(2,input:gsub('^' .. word .. '$','')) +
|
||||
select(2,input:gsub('%W+' .. word .. '%W+','')) > 0
|
||||
end
|
||||
|
||||
function notify:pre_process(msg, self)
|
||||
local notify_users = redis:smembers('notify:ls')
|
||||
|
||||
-- I call this beautiful lady the "if soup"
|
||||
if msg.chat.type == 'chat' or msg.chat.type == 'supergroup' then
|
||||
if msg.text then
|
||||
for _,user in pairs(notify_users) do
|
||||
if isWordFoundInString('@'..user, string.lower(msg.text)) then
|
||||
local chat_id = msg.chat.id
|
||||
local id = redis:hget('notify:'..user, 'id')
|
||||
-- check, if user has sent at least one message to the group,
|
||||
-- so that we don't send the user some private text, when he/she is not
|
||||
-- in the group.
|
||||
if redis:sismember('chat:'..chat_id..':users', id) then
|
||||
|
||||
-- ignore message, if user is mentioning him/herself
|
||||
if id == tostring(msg.from.id) then break; end
|
||||
|
||||
local send_date = run_command('date -d @'..msg.date..' +"%d.%m.%Y um %H:%M:%S Uhr"')
|
||||
local send_date = string.gsub(send_date, "\n", "")
|
||||
local from = string.gsub(msg.from.name, "%_", " ")
|
||||
local chat_name = string.gsub(msg.chat.title, "%_", " ")
|
||||
local text = from..' am '..send_date..' in "'..chat_name..'":\n\n'..msg.text
|
||||
utilities.send_message(self, id, text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function notify:action(msg, config, matches)
|
||||
if not msg.from.username then
|
||||
utilities.send_reply(self, msg, 'Du hast keinen Usernamen und kannst daher dieses Feature nicht nutzen. Tut mir leid!' )
|
||||
return
|
||||
end
|
||||
|
||||
local username = string.lower(msg.from.username)
|
||||
|
||||
local hash = 'notify:'..username
|
||||
|
||||
if matches[1] == "del" then
|
||||
if not redis:sismember('notify:ls', username) then
|
||||
utilities.send_reply(self, msg, 'Du wirst noch gar nicht benachrichtigt!')
|
||||
return
|
||||
end
|
||||
print('Setting notify in redis hash '..hash..' to false')
|
||||
redis:hset(hash, 'notify', false)
|
||||
print('Removing '..username..' from redis set notify:ls')
|
||||
redis:srem('notify:ls', username)
|
||||
utilities.send_reply(self, msg, 'Du erhälst jetzt keine Benachrichtigungen mehr, wenn du angesprochen wirst.')
|
||||
return
|
||||
else
|
||||
if redis:sismember('notify:ls', username) then
|
||||
utilities.send_reply(self, msg, 'Du wirst schon benachrichtigt!')
|
||||
return
|
||||
end
|
||||
print('Setting notify in redis hash '..hash..' to true')
|
||||
redis:hset(hash, 'notify', true)
|
||||
print('Setting id in redis hash '..hash..' to '..msg.from.id)
|
||||
redis:hset(hash, 'id', msg.from.id)
|
||||
print('Adding '..username..' to redis set notify:ls')
|
||||
redis:sadd('notify:ls', username)
|
||||
local res = utilities.send_message(self, msg.from.id, 'Du erhälst jetzt Benachrichtigungen, wenn du angesprochen wirst, nutze `/notify del` zum Deaktivieren.', true, nil, true)
|
||||
if not res then
|
||||
utilities.send_reply(self, msg, 'Bitte schreibe mir [privat](http://telegram.me/' .. self.info.username .. '?start=notify), um den Vorgang abzuschließen.', true)
|
||||
elseif msg.chat.type ~= 'private' then
|
||||
utilities.send_reply(self, msg, 'Du erhälst jetzt Benachrichtigungen, wenn du angesprochen wirst, nutze `/notify del` zum Deaktivieren.', true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return notify
|
39
miku/plugins/pagespeed_insights.lua
Normal file
39
miku/plugins/pagespeed_insights.lua
Normal file
@ -0,0 +1,39 @@
|
||||
local pagespeed_insights = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function pagespeed_insights:init(config)
|
||||
if not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('pagespeed_insights.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
pagespeed_insights.triggers = {
|
||||
"^/speed (https?://[%w-_%.%?%.:/%+=&]+)"
|
||||
}
|
||||
pagespeed_insights.doc = [[*
|
||||
]]..config.cmd_pat..[[speed* _<Seiten-URL>_: Testet Geschwindigkeit der Seite mit PageSpeed Insights]]
|
||||
end
|
||||
|
||||
local BASE_URL = 'https://www.googleapis.com/pagespeedonline/v2'
|
||||
|
||||
function pagespeed_insights:get_pagespeed(test_url)
|
||||
local apikey = cred_data.google_apikey
|
||||
local url = BASE_URL..'/runPagespeed?url='..test_url..'&key='..apikey..'&fields=id,ruleGroups(SPEED(score))'
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return "HTTP-FEHLER" end
|
||||
local data = json.decode(res)
|
||||
return data.id..' hat einen PageSpeed-Score von *'..data.ruleGroups.SPEED.score..' Punkten.*'
|
||||
end
|
||||
|
||||
function pagespeed_insights:action(msg, config, matches)
|
||||
utilities.send_typing(self, msg.chat.id, 'typing')
|
||||
local text = pagespeed_insights:get_pagespeed(matches[1])
|
||||
if not text then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return pagespeed_insights
|
@ -1,7 +1,7 @@
|
||||
local pasteee = {}
|
||||
|
||||
local bot = require('otouto.bot')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bot = require('miku.bot')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function pasteee:init(config)
|
||||
if not cred_data.pasteee_key then
|
120
miku/plugins/pixabay.lua
Normal file
120
miku/plugins/pixabay.lua
Normal file
@ -0,0 +1,120 @@
|
||||
local pixabay = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function pixabay:init(config)
|
||||
if not cred_data.pixabay_apikey then
|
||||
print('Missing config value: pixabay_apikey.')
|
||||
print('pixabay.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
pixabay.triggers = {
|
||||
"^/pix(id) (%d+)",
|
||||
"^/pix (.*)$",
|
||||
"(pixabay.com).*%-(%d+)"
|
||||
}
|
||||
pixabay.doc = [[*
|
||||
]]..config.cmd_pat..[[pix* _<Suchbegriff>_: Sendet lizenzfreies Bild]]
|
||||
end
|
||||
|
||||
pixabay.command = 'pix <Suchbegriff>'
|
||||
|
||||
local BASE_URL = 'https://pixabay.com/api'
|
||||
local apikey = cred_data.pixabay_apikey
|
||||
|
||||
function pixabay:get_pixabay_directlink(id)
|
||||
local url = BASE_URL..'/?key='..apikey..'&lang=de&id='..id
|
||||
local b,c = https.request(url)
|
||||
if c ~= 200 then return nil end
|
||||
local data = json.decode(b)
|
||||
if data.totalHits == 0 then return 'NOPIX' end
|
||||
|
||||
local webformatURL = data.hits[1].webformatURL
|
||||
local image_url = string.gsub(webformatURL, '_640.jpg', '_960.jpg')
|
||||
|
||||
-- Link to full, high resolution image
|
||||
local preview_url = data.hits[1].previewURL
|
||||
local image_code = string.sub(preview_url, 59)
|
||||
local image_code = string.sub(image_code, 0, -9)
|
||||
local full_url = 'https://pixabay.com/de/photos/download/'..image_code..'.jpg'
|
||||
|
||||
local user = data.hits[1].user
|
||||
local tags = data.hits[1].tags
|
||||
local page_url = data.hits[1].pageURL
|
||||
|
||||
-- cache this shit
|
||||
local hash = 'telegram:cache:pixabay:'..id
|
||||
print('Caching data in '..hash..' with timeout 1209600')
|
||||
redis:hset(hash, 'image_url', image_url)
|
||||
redis:hset(hash, 'full_url', full_url)
|
||||
redis:hset(hash, 'page_url', page_url)
|
||||
redis:hset(hash, 'user', user)
|
||||
redis:hset(hash, 'tags', tags)
|
||||
redis:expire(hash, 1209600) -- 1209600 = two weeks
|
||||
|
||||
return image_url, full_url, page_url, user, tags
|
||||
end
|
||||
|
||||
function pixabay:get_pixabay(term)
|
||||
local count = 70 -- how many pictures should be returned (3 to 200) NOTE: more pictures = higher load time
|
||||
local url = BASE_URL..'/?key='..apikey..'&lang=de&safesearch=true&per_page='..count..'&image_type=photo&q='..term
|
||||
local b,c = https.request(url)
|
||||
if c ~= 200 then return nil end
|
||||
local photo = json.decode(b)
|
||||
if photo.totalHits == 0 then return 'NOPIX' end
|
||||
local photos = photo.hits
|
||||
-- truly randomize
|
||||
math.randomseed(os.time())
|
||||
-- random max json table size
|
||||
local i = math.random(#photos)
|
||||
|
||||
local webformatURL = photos[i].webformatURL
|
||||
local image_url = string.gsub(webformatURL, '_640.jpg', '_960.jpg')
|
||||
|
||||
-- Link to full, high resolution image
|
||||
local preview_url = photos[i].previewURL
|
||||
local image_code = string.sub(preview_url, 59)
|
||||
local image_code = string.sub(image_code, 0, -9)
|
||||
local full_url = 'https://pixabay.com/de/photos/download/'..image_code..'.jpg'
|
||||
|
||||
local user = photos[i].user
|
||||
local tags = photos[i].tags
|
||||
local page_url = photos[i].pageURL
|
||||
|
||||
return image_url, full_url, page_url, user, tags
|
||||
end
|
||||
|
||||
function pixabay:action(msg, config, matches)
|
||||
local term = matches[1]
|
||||
if matches[2] then
|
||||
if redis:exists("telegram:cache:pixabay:"..matches[2]) == true then -- if cached
|
||||
local hash = 'telegram:cache:pixabay:'..matches[2]
|
||||
url = redis:hget(hash, 'image_url')
|
||||
full_url = redis:hget(hash, 'full_url')
|
||||
page_url = redis:hget(hash, 'page_url')
|
||||
user = redis:hget(hash, 'user')
|
||||
tags = redis:hget(hash, 'tags')
|
||||
else
|
||||
url, full_url, page_url, user, tags = pixabay:get_pixabay_directlink(matches[2])
|
||||
end
|
||||
else
|
||||
url, full_url, page_url, user, tags = pixabay:get_pixabay(term)
|
||||
end
|
||||
|
||||
if url == 'NOPIX' then
|
||||
utilities.send_reply(self, msg, config.errors.results)
|
||||
return
|
||||
else
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(url)
|
||||
local text = '"'..tags..'" von '..user
|
||||
utilities.send_photo(self, msg.chat.id, file, text, msg.message_id, '{"inline_keyboard":[[{"text":"Seite aufrufen","url":"'..page_url..'"},{"text":"Volles Bild (Login notwendig)","url":"'..full_url..'"}]]}')
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return pixabay
|
62
miku/plugins/play_store.lua
Normal file
62
miku/plugins/play_store.lua
Normal file
@ -0,0 +1,62 @@
|
||||
local play_store = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function play_store:init(config)
|
||||
if not cred_data.x_mashape_key then
|
||||
print('Missing config value: x_mashape_key.')
|
||||
print('play_store.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
play_store.triggers = {
|
||||
"play.google.com/store/apps/details%?id=(.*)"
|
||||
}
|
||||
end
|
||||
|
||||
local BASE_URL = 'https://apps.p.mashape.com/google/application'
|
||||
|
||||
function play_store:get_playstore_data (appid)
|
||||
local apikey = cred_data.x_mashape_key
|
||||
local url = BASE_URL..'/'..appid..'?mashape-key='..apikey
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res).data
|
||||
return data
|
||||
end
|
||||
|
||||
function play_store:send_playstore_data(data)
|
||||
local title = data.title
|
||||
local developer = data.developer.id
|
||||
local category = data.category.name
|
||||
local rating = data.rating.average
|
||||
local installs = data.performance.installs
|
||||
local description = data.description
|
||||
if data.version == "Varies with device" then
|
||||
appversion = "variiert je nach Gerät"
|
||||
else
|
||||
appversion = data.version
|
||||
end
|
||||
if data.price == 0 then
|
||||
price = "Gratis"
|
||||
else
|
||||
price = data.price
|
||||
end
|
||||
local text = '*'..title..'* von *'..developer..'* aus der Kategorie _'..category..'_, durschnittlich bewertet mit '..rating..' Sternen.\n_'..description..'_\n'..installs..' Installationen, Version '..appversion
|
||||
return text
|
||||
end
|
||||
|
||||
function play_store:action(msg, config, matches)
|
||||
local appid = matches[1]
|
||||
local data = play_store:get_playstore_data(appid)
|
||||
if data == nil then
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, play_store:send_playstore_data(data), true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return play_store
|
230
miku/plugins/plugins.lua
Normal file
230
miku/plugins/plugins.lua
Normal file
@ -0,0 +1,230 @@
|
||||
local plugin_manager = {}
|
||||
|
||||
local bot = require('miku.bot')
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
function plugin_manager:init(config)
|
||||
plugin_manager.triggers = {
|
||||
"^/plugins$",
|
||||
"^/plugins? (enable) ([%w_%.%-]+)$",
|
||||
"^/plugins? (disable) ([%w_%.%-]+)$",
|
||||
"^/plugins? (enable) ([%w_%.%-]+) (chat) (%d+)",
|
||||
"^/plugins? (enable) ([%w_%.%-]+) (chat)",
|
||||
"^/plugins? (disable) ([%w_%.%-]+) (chat) (%d+)",
|
||||
"^/plugins? (disable) ([%w_%.%-]+) (chat)",
|
||||
"^/plugins? (reload)$",
|
||||
"^/(reload)$"
|
||||
}
|
||||
plugin_manager.doc = [[*
|
||||
]]..config.cmd_pat..[[plugins*: Listet alle Plugins auf
|
||||
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_: Aktiviert/deaktiviert Plugin
|
||||
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_ chat: Aktiviert/deaktiviert Plugin im aktuellen Chat
|
||||
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_ _<chat#id>_: Aktiviert/deaktiviert Plugin in diesem Chat
|
||||
*]]..config.cmd_pat..[[reload*: Lädt Plugins neu]]
|
||||
end
|
||||
|
||||
plugin_manager.command = 'plugins <nur für Superuser>'
|
||||
|
||||
-- Returns the key (index) in the config.enabled_plugins table
|
||||
function plugin_manager:plugin_enabled(name, chat)
|
||||
for k,v in pairs(enabled_plugins) do
|
||||
if name == v then
|
||||
return k
|
||||
end
|
||||
end
|
||||
-- If not found
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns true if file exists in plugins folder
|
||||
function plugin_manager:plugin_exists(name)
|
||||
for k,v in pairs(plugins_names()) do
|
||||
if name..'.lua' == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function plugin_manager:list_plugins()
|
||||
local text = ''
|
||||
for k, v in pairs(plugins_names()) do
|
||||
-- ✔ enabled, ❌ disabled
|
||||
local status = '❌'
|
||||
-- Check if is enabled
|
||||
for k2, v2 in pairs(enabled_plugins) do
|
||||
if v == v2..'.lua' then
|
||||
status = '✔'
|
||||
end
|
||||
end
|
||||
if not only_enabled or status == '✔' then
|
||||
-- get the name
|
||||
v = string.match (v, "(.*)%.lua")
|
||||
text = text..v..' '..status..'\n'
|
||||
end
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
function plugin_manager:reload_plugins(self, config, plugin_name, status)
|
||||
for pac, _ in pairs(package.loaded) do
|
||||
if pac:match('^miku%.plugins%.') then
|
||||
package.loaded[pac] = nil
|
||||
end
|
||||
end
|
||||
package.loaded['miku.bindings'] = nil
|
||||
package.loaded['miku.utilities'] = nil
|
||||
package.loaded['config'] = nil
|
||||
bot.init(self, config)
|
||||
if plugin_name then
|
||||
return 'Plugin '..plugin_name..' wurde '..status
|
||||
else
|
||||
return 'Plugins neu geladen'
|
||||
end
|
||||
end
|
||||
|
||||
function plugin_manager:enable_plugin(self, config, plugin_name)
|
||||
print('checking if '..plugin_name..' exists')
|
||||
-- Check if plugin is enabled
|
||||
if plugin_manager:plugin_enabled(plugin_name) then
|
||||
return 'Plugin '..plugin_name..' ist schon aktiviert'
|
||||
end
|
||||
-- Checks if plugin exists
|
||||
if plugin_manager:plugin_exists(plugin_name) then
|
||||
-- Add to redis set
|
||||
redis:sadd('telegram:enabled_plugins', plugin_name)
|
||||
print(plugin_name..' saved to redis set telegram:enabled_plugins')
|
||||
-- Reload the plugins
|
||||
return plugin_manager:reload_plugins(self, config, plugin_name, 'aktiviert')
|
||||
else
|
||||
return 'Plugin '..plugin_name..' existiert nicht'
|
||||
end
|
||||
end
|
||||
|
||||
function plugin_manager:disable_plugin(self, config, name, chat)
|
||||
-- Check if plugins exists
|
||||
if not plugin_manager:plugin_exists(name) then
|
||||
return 'Plugin '..name..' existiert nicht'
|
||||
end
|
||||
local k = plugin_manager:plugin_enabled(name)
|
||||
-- Check if plugin is enabled
|
||||
if not k then
|
||||
return 'Plugin '..name..' ist nicht aktiviert'
|
||||
end
|
||||
-- Disable and reload
|
||||
redis:srem('telegram:enabled_plugins', name)
|
||||
print(name..' saved to redis set telegram:enabled_plugins')
|
||||
return plugin_manager:reload_plugins(self, config, name, 'deaktiviert')
|
||||
end
|
||||
|
||||
function plugin_manager:disable_plugin_on_chat(msg, plugin)
|
||||
if not plugin_manager:plugin_exists(plugin) then
|
||||
return "Plugin existiert nicht!"
|
||||
end
|
||||
|
||||
if not msg.chat then
|
||||
hash = 'chat:'..msg..':disabled_plugins'
|
||||
else
|
||||
hash = get_redis_hash(msg, 'disabled_plugins')
|
||||
end
|
||||
local disabled = redis:hget(hash, plugin)
|
||||
|
||||
if disabled ~= 'true' then
|
||||
print('Setting '..plugin..' in redis hash '..hash..' to true')
|
||||
redis:hset(hash, plugin, true)
|
||||
return 'Plugin '..plugin..' für diesen Chat deaktiviert.'
|
||||
else
|
||||
return 'Plugin '..plugin..' wurde für diesen Chat bereits deaktiviert.'
|
||||
end
|
||||
end
|
||||
|
||||
function plugin_manager:reenable_plugin_on_chat(msg, plugin)
|
||||
if not plugin_manager:plugin_exists(plugin) then
|
||||
return "Plugin existiert nicht!"
|
||||
end
|
||||
|
||||
if not msg.chat then
|
||||
hash = 'chat:'..msg..':disabled_plugins'
|
||||
else
|
||||
hash = get_redis_hash(msg, 'disabled_plugins')
|
||||
end
|
||||
local disabled = redis:hget(hash, plugin)
|
||||
|
||||
if disabled == nil then return 'Es gibt keine deaktivierten Plugins für disen Chat.' end
|
||||
|
||||
if disabled == 'true' then
|
||||
print('Setting '..plugin..' in redis hash '..hash..' to false')
|
||||
redis:hset(hash, plugin, false)
|
||||
return 'Plugin '..plugin..' wurde für diesen Chat reaktiviert.'
|
||||
else
|
||||
return 'Plugin '..plugin..' ist nicht deaktiviert.'
|
||||
end
|
||||
end
|
||||
|
||||
function plugin_manager:action(msg, config, matches)
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
|
||||
-- Show the available plugins
|
||||
if matches[1] == '/plugins' then
|
||||
utilities.send_reply(self, msg, plugin_manager:list_plugins())
|
||||
return
|
||||
end
|
||||
|
||||
-- Reenable a plugin for this chat
|
||||
if matches[1] == 'enable' and matches[3] == 'chat' then
|
||||
local plugin = matches[2]
|
||||
if matches[4] then
|
||||
local id = matches[4]
|
||||
print("enable "..plugin..' on chat#id'..id)
|
||||
utilities.send_reply(self, msg, plugin_manager:reenable_plugin_on_chat(id, plugin))
|
||||
return
|
||||
else
|
||||
print("enable "..plugin..' on this chat')
|
||||
utilities.send_reply(self, msg, plugin_manager:reenable_plugin_on_chat(msg, plugin))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Enable a plugin
|
||||
if matches[1] == 'enable' then
|
||||
local plugin_name = matches[2]
|
||||
print("enable: "..matches[2])
|
||||
utilities.send_reply(self, msg, plugin_manager:enable_plugin(self, config, plugin_name))
|
||||
return
|
||||
end
|
||||
|
||||
-- Disable a plugin on a chat
|
||||
if matches[1] == 'disable' and matches[3] == 'chat' then
|
||||
local plugin = matches[2]
|
||||
if matches[4] then
|
||||
local id = matches[4]
|
||||
print("disable "..plugin..' on chat#id'..id)
|
||||
utilities.send_reply(self, msg, plugin_manager:disable_plugin_on_chat(id, plugin))
|
||||
return
|
||||
else
|
||||
print("disable "..plugin..' on this chat')
|
||||
utilities.send_reply(self, msg, plugin_manager:disable_plugin_on_chat(msg, plugin))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Disable a plugin
|
||||
if matches[1] == 'disable' then
|
||||
print("disable: "..matches[2])
|
||||
utilities.send_reply(self, msg, plugin_manager:disable_plugin(self, config, matches[2]))
|
||||
return
|
||||
end
|
||||
|
||||
-- Reload all the plugins!
|
||||
if matches[1] == 'reload' then
|
||||
utilities.send_reply(self, msg, plugin_manager:reload_plugins(self, config))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return plugin_manager
|
149
miku/plugins/pocket.lua
Normal file
149
miku/plugins/pocket.lua
Normal file
@ -0,0 +1,149 @@
|
||||
local pocket = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function pocket:init(config)
|
||||
if not cred_data.pocket_consumer_key then
|
||||
print('Missing config value: pocket_consumer_key.')
|
||||
print('pocket.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
pocket.triggers = {
|
||||
"^/pocket(set)(.+)$",
|
||||
"^/pocket (add) (https?://.*)$",
|
||||
"^/pocket (archive) (%d+)$",
|
||||
"^/pocket (readd) (%d+)$",
|
||||
"^/pocket (unfavorite) (%d+)$",
|
||||
"^/pocket (favorite) (%d+)$",
|
||||
"^/pocket (delete) (%d+)$",
|
||||
"^/pocket (unauth)$",
|
||||
"^/pocket$"
|
||||
}
|
||||
|
||||
pocket.doc = [[*
|
||||
]]..config.cmd_pat..[[pocket*: Postet Liste deiner Links
|
||||
*]]..config.cmd_pat..[[pocket* add _(url)_: Fügt diese URL deiner Liste hinzu
|
||||
*]]..config.cmd_pat..[[pocket* archive _[id]_: Archiviere diesen Eintrag
|
||||
*]]..config.cmd_pat..[[pocket* readd _[id]_: De-archiviere diesen Eintrag
|
||||
*]]..config.cmd_pat..[[pocket* favorite _[id]_: Favorisiere diesen Eintrag
|
||||
*]]..config.cmd_pat..[[pocket* unfavorite _[id]_: Entfavorisiere diesen Eintrag
|
||||
*]]..config.cmd_pat..[[pocket* delete _[id]_: Lösche diesen Eintrag
|
||||
*]]..config.cmd_pat..[[pocket* unauth: Löscht deinen Account aus dem Bot]]
|
||||
end
|
||||
|
||||
pocket.command = 'pocket <siehe `/hilfe pocket`>'
|
||||
|
||||
local BASE_URL = 'https://getpocket.com/v3'
|
||||
local consumer_key = cred_data.pocket_consumer_key
|
||||
local headers = {
|
||||
["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF8",
|
||||
["X-Accept"] = "application/json"
|
||||
}
|
||||
|
||||
function pocket:set_pocket_access_token(hash, access_token)
|
||||
if string.len(access_token) ~= 30 then return '*Inkorrekter Access-Token*' end
|
||||
print('Setting pocket in redis hash '..hash..' to users access_token')
|
||||
redis:hset(hash, 'pocket', access_token)
|
||||
return '*Authentifizierung abgeschlossen!*\nDas Plugin kann jetzt verwendet werden.'
|
||||
end
|
||||
|
||||
function pocket:list_pocket_items(access_token)
|
||||
local items = post_petition(BASE_URL..'/get', 'consumer_key='..consumer_key..'&access_token='..access_token..'&state=unread&sort=newest&detailType=simple', headers)
|
||||
|
||||
if items.status == 2 then return 'Keine Elemente eingespeichert.' end
|
||||
if items.status ~= 1 then return 'Ein Fehler beim Holen der Elemente ist aufgetreten.' end
|
||||
|
||||
local text = ''
|
||||
for element in pairs(items.list) do
|
||||
title = items.list[element].given_title
|
||||
if not title or title == "" then title = items.list[element].resolved_title end
|
||||
text = text..'#'..items.list[element].item_id..': '..title..'\n— '..items.list[element].resolved_url..'\n\n'
|
||||
end
|
||||
|
||||
return text
|
||||
end
|
||||
|
||||
function pocket:add_pocket_item(access_token, url)
|
||||
local result = post_petition(BASE_URL..'/add', 'consumer_key='..consumer_key..'&access_token='..access_token..'&url='..url, headers)
|
||||
if result.status ~= 1 then return 'Ein Fehler beim Hinzufügen der URL ist aufgetreten :(' end
|
||||
local given_url = result.item.given_url
|
||||
if result.item.title == "" or not result.item.title then
|
||||
title = 'Seite'
|
||||
else
|
||||
title = '"'..result.item.title..'"'
|
||||
end
|
||||
local code = result.item.response_code
|
||||
|
||||
local text = title..' ('..given_url..') hinzugefügt!'
|
||||
if code ~= "200" and code ~= "0" then text = text..'\nAber die Seite liefert Fehler '..code..' zurück.' end
|
||||
return text
|
||||
end
|
||||
|
||||
function pocket:modify_pocket_item(access_token, action, id)
|
||||
local result = post_petition(BASE_URL..'/send', 'consumer_key='..consumer_key..'&access_token='..access_token..'&actions=[{"action":"'..action..'","item_id":'..id..'}]', headers)
|
||||
if result.status ~= 1 then return 'Ein Fehler ist aufgetreten :(' end
|
||||
|
||||
if action == 'readd' then
|
||||
if result.action_results[1] == false then
|
||||
return 'Dieser Eintrag existiert nicht!'
|
||||
end
|
||||
local url = result.action_results[1].normal_url
|
||||
return url..' wieder de-archiviert'
|
||||
end
|
||||
if result.action_results[1] == true then
|
||||
return 'Aktion ausgeführt.'
|
||||
else
|
||||
return 'Ein Fehler ist aufgetreten.'
|
||||
end
|
||||
end
|
||||
|
||||
function pocket:action(msg, config, matches)
|
||||
local hash = 'user:'..msg.from.id
|
||||
local access_token = redis:hget(hash, 'pocket')
|
||||
|
||||
if matches[1] == 'set' then
|
||||
local access_token = matches[2]
|
||||
utilities.send_reply(self, msg, pocket:set_pocket_access_token(hash, access_token), true)
|
||||
local message_id = redis:hget(hash, 'pocket_login_msg')
|
||||
utilities.edit_message(self, msg.chat.id, message_id, '*Anmeldung abgeschlossen!*', true, true)
|
||||
redis:hdel(hash, 'pocket_login_msg')
|
||||
return
|
||||
end
|
||||
|
||||
if not access_token then
|
||||
local result = utilities.send_reply(self, msg, '*Bitte authentifiziere dich zuerst, indem du dich anmeldest.*', true, '{"inline_keyboard":[[{"text":"Bei Pocket anmelden","url":"https://brawlbot.tk/apis/callback/pocket/connect.php"}]]}')
|
||||
redis:hset(hash, 'pocket_login_msg', result.result.message_id)
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'unauth' then
|
||||
redis:hdel(hash, 'pocket')
|
||||
utilities.send_reply(self, msg, 'Erfolgreich ausgeloggt! Du kannst den Zugriff [in deinen Einstellungen](https://getpocket.com/connected_applications) endgültig entziehen.', true)
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'add' then
|
||||
utilities.send_reply(self, msg, pocket:add_pocket_item(access_token, matches[2]))
|
||||
return
|
||||
end
|
||||
|
||||
if matches[1] == 'archive' or matches[1] == 'delete' or matches[1] == 'readd' or matches[1] == 'favorite' or matches[1] == 'unfavorite' then
|
||||
utilities.send_reply(self, msg, pocket:modify_pocket_item(access_token, matches[1], matches[2]))
|
||||
return
|
||||
end
|
||||
|
||||
if msg.chat.type == 'chat' or msg.chat.type == 'supergroup' then
|
||||
utilities.send_reply(self, msg, 'Ausgeben deiner privaten Pocket-Liste in einem öffentlichen Chat wird feige verweigert. Bitte schreibe mich privat an!', true)
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, pocket:list_pocket_items(access_token))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
return pocket
|
@ -2,8 +2,8 @@ local pokedex = {}
|
||||
|
||||
local HTTP = require('socket.http')
|
||||
local JSON = require('dkjson')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
pokedex.command = 'pokedex <query>'
|
||||
|
@ -1,7 +1,7 @@
|
||||
local preview = {}
|
||||
|
||||
local HTTP = require('socket.http')
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
preview.command = 'preview <link>'
|
||||
|
86
miku/plugins/qr.lua
Normal file
86
miku/plugins/qr.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local qr = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local URL = require('socket.url')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function qr:init(config)
|
||||
qr.triggers = {
|
||||
'^/qr "(%w+)" "(%w+)" (.+)$',
|
||||
"^/qr (.+)$"
|
||||
}
|
||||
qr.doc = [[*
|
||||
]]..config.cmd_pat..[[qr* _<Text>_: Sendet QR-Code mit diesem Text
|
||||
*]]..config.cmd_pat..[[qr* _"[Hintergrundfarbe]"_ _"[Datenfarbe]"_ _[Text]_
|
||||
Farbe mit Text: red|green|blue|purple|black|white|gray
|
||||
Farbe als HEX: ("a56729" ist braun)
|
||||
oder Farbe als Dezimalwert: ("255-192-203" ist pink)]]
|
||||
end
|
||||
|
||||
qr.command = 'qr <Text>'
|
||||
|
||||
function qr:get_hex(str)
|
||||
local colors = {
|
||||
red = "f00",
|
||||
blue = "00f",
|
||||
green = "0f0",
|
||||
yellow = "ff0",
|
||||
purple = "f0f",
|
||||
white = "fff",
|
||||
black = "000",
|
||||
gray = "ccc"
|
||||
}
|
||||
|
||||
for color, value in pairs(colors) do
|
||||
if color == str then
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
function qr:qr(text, color, bgcolor)
|
||||
|
||||
local url = "http://api.qrserver.com/v1/create-qr-code/?"
|
||||
.."size=600x600" --fixed size otherways it's low detailed
|
||||
.."&data="..URL.escape(utilities.trim(text))
|
||||
|
||||
if color then
|
||||
url = url.."&color="..qr:get_hex(color)
|
||||
end
|
||||
if bgcolor then
|
||||
url = url.."&bgcolor="..qr:get_hex(bgcolor)
|
||||
end
|
||||
|
||||
local response, code, headers = http.request(url)
|
||||
|
||||
if code ~= 200 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if #response > 0 then
|
||||
return url
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function qr:action(msg, config, matches)
|
||||
local text = matches[1]
|
||||
local color
|
||||
local back
|
||||
|
||||
if #matches > 1 then
|
||||
text = matches[3]
|
||||
color = matches[2]
|
||||
back = matches[1]
|
||||
end
|
||||
|
||||
local image_url = qr:qr(text, color, back)
|
||||
if not image_url then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
local file = download_to_file(image_url, 'qr.png')
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
|
||||
return qr
|
@ -1,9 +1,9 @@
|
||||
local quotes = {}
|
||||
|
||||
local bot = require('otouto.bot')
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
require("./otouto/plugins/pasteee")
|
||||
local bot = require('miku.bot')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
require("./miku/plugins/pasteee")
|
||||
|
||||
function quotes:init(config)
|
||||
quotes.triggers = {
|
||||
@ -75,7 +75,7 @@ function quotes:list_quotes(msg)
|
||||
text = text..num..") "..quote..'\n'
|
||||
end
|
||||
if not text or text == "" then
|
||||
return 'Es wurden noch keine Zitate gespeichert.\nSpeichere doch welche mit !addquote [Zitat]'
|
||||
return '*Es wurden noch keine Zitate gespeichert.*\nSpeichere doch welche mit `/addquote [Zitat]`', true
|
||||
else
|
||||
return upload(text)
|
||||
end
|
||||
@ -99,10 +99,10 @@ function quotes:action(msg, config, matches)
|
||||
elseif matches[1] == "listquotes" then
|
||||
local link, iserror = quotes:list_quotes(msg)
|
||||
if iserror then
|
||||
utilities.send_reply(self, msg, link)
|
||||
utilities.send_reply(self, msg, link, true)
|
||||
return
|
||||
end
|
||||
utilities.send_reply(self, msg, '[Lise aller Zitate auf Paste.ee ansehen]('..link..')', true)
|
||||
utilities.send_reply(self, msg, 'Ich habe eine Liste aller Zitate hochgeladen.', false, '{"inline_keyboard":[[{"text":"Alle Zitate abrufen","url":"'..link..'"}]]}')
|
||||
return
|
||||
end
|
||||
utilities.send_reply(self, msg, quotes.doc, true)
|
67
miku/plugins/random.lua
Normal file
67
miku/plugins/random.lua
Normal file
@ -0,0 +1,67 @@
|
||||
local fun = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function fun:init(config)
|
||||
fun.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('random', true).table
|
||||
fun.doc = [[*
|
||||
]]..config.cmd_pat..[[random* _<Username>_: Schau, was passiert!]]
|
||||
end
|
||||
|
||||
fun.command = 'random <Username>'
|
||||
|
||||
function fun:choose_random(user_name, other_user)
|
||||
randoms = {
|
||||
user_name..' schlägt '..other_user..' mit einem stinkenden Fisch.',
|
||||
user_name..' versucht, '..other_user..' mit einem Messer zu töten, bringt sich dabei aber selbst um.',
|
||||
user_name..' versucht, '..other_user..' mit einem Messer zu töten, stolpert aber und schlitzt sich dabei das Knie auf.',
|
||||
user_name..' ersticht '..other_user..'.',
|
||||
user_name..' tritt '..other_user..'.',
|
||||
user_name..' hat '..other_user..' umgebracht! Möge er in der Hölle schmoren!',
|
||||
user_name..' hat die Schnauze voll von '..other_user..' und sperrt ihn in einen Schrank.',
|
||||
user_name..' erwürgt '..other_user..'. BILD sprach als erstes mit der Hand.',
|
||||
user_name..' schickt '..other_user..' nach /dev/null.',
|
||||
user_name..' umarmt '..other_user..'.',
|
||||
user_name..' verschenkt eine Kartoffel an '..other_user..'.',
|
||||
user_name..' melkt '..other_user..'. *muuh* :D',
|
||||
user_name..' wirft einen Gameboy auf '..other_user..'.',
|
||||
user_name..' hetzt die NSA auf '..other_user..'.',
|
||||
user_name..' ersetzt alle CDs von '..other_user..' durch Nickelback-CDs.',
|
||||
other_user..' melkt '..user_name..'. *muuh* :D',
|
||||
user_name..' ist in '..other_user..' verliebt.',
|
||||
user_name..' schmeißt '..other_user..' in einen Fluss.',
|
||||
user_name..' klaut '..other_user..' einen Lolli.',
|
||||
user_name..' hätte gern Sex mit '..other_user..'.',
|
||||
user_name..' schenkt '..other_user..' ein Foto von seinem Penis.',
|
||||
user_name..' dreht durch und wirft '..other_user..' in einen Häcksler.',
|
||||
user_name..' gibt '..other_user..' einen Keks.',
|
||||
user_name..' lacht '..other_user..' aus.',
|
||||
user_name..' gibt '..other_user..[[ ganz viel Liebe. ( ͡° ͜ʖ ͡°)]],
|
||||
user_name..' lädt '..other_user..' zum Essen ein.',
|
||||
user_name..' schwatzt '..other_user..' Ubuntu auf.',
|
||||
user_name..' fliegt mit '..other_user..' nach Hawaii.',
|
||||
user_name..' küsst '..other_user..' leidenschaftlich.'
|
||||
}
|
||||
math.randomseed(os.time())
|
||||
math.randomseed(os.time())
|
||||
local random = math.random(#randoms)
|
||||
return randoms[random]
|
||||
end
|
||||
|
||||
function fun:action(msg, config, matches)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, fun.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local user_name = get_name(msg)
|
||||
local result = fun:choose_random(user_name, input)
|
||||
utilities.send_message(self, msg.chat.id, result)
|
||||
end
|
||||
|
||||
return fun
|
@ -1,19 +1,16 @@
|
||||
local reddit = {}
|
||||
|
||||
local HTTP = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
reddit.command = 'reddit [r/subreddit | query]'
|
||||
reddit.command = 'reddit [r/subreddit | Suchbegriff]'
|
||||
|
||||
function reddit:init(config)
|
||||
reddit.triggers = utilities.triggers(self.info.username, config.cmd_pat, {'^/r/'}):t('reddit', true):t('r', true):t('r/', true).table
|
||||
reddit.doc = [[```
|
||||
]]..config.cmd_pat..[[reddit [r/subreddit | query]
|
||||
Returns the top posts or results for a given subreddit or query. If no argument is given, returns the top posts from r/all. Querying specific subreddits is not supported.
|
||||
Aliases: ]]..config.cmd_pat..[[r, /r/subreddit
|
||||
```]]
|
||||
reddit.doc = [[*
|
||||
]]..config.cmd_pat..[[r* _[r/subreddit | Suchbegriff]_: Gibt Top-Posts oder Ergebnisse eines Subreddits aus. Wenn kein Argument gegeben ist, wird /r/all genommen.]]
|
||||
end
|
||||
|
||||
local format_results = function(posts)
|
||||
@ -25,8 +22,8 @@ local format_results = function(posts)
|
||||
title = title:sub(1, 253)
|
||||
title = utilities.trim(title) .. '...'
|
||||
end
|
||||
local short_url = 'redd.it/' .. post.id
|
||||
local s = '[' .. title .. '](' .. short_url .. ')'
|
||||
local short_url = 'https://redd.it/' .. post.id
|
||||
local s = '[' .. unescape(title) .. '](' .. short_url .. ')'
|
||||
if post.domain and not post.is_self and not post.over_18 then
|
||||
s = '`[`[' .. post.domain .. '](' .. post.url:gsub('%)', '\\)') .. ')`]` ' .. s
|
||||
end
|
||||
@ -35,9 +32,9 @@ local format_results = function(posts)
|
||||
return output
|
||||
end
|
||||
|
||||
reddit.subreddit_url = 'http://www.reddit.com/%s/.json?limit='
|
||||
reddit.search_url = 'http://www.reddit.com/search.json?q=%s&limit='
|
||||
reddit.rall_url = 'http://www.reddit.com/.json?limit='
|
||||
reddit.subreddit_url = 'https://www.reddit.com/%s/.json?limit='
|
||||
reddit.search_url = 'https://www.reddit.com/search.json?q=%s&limit='
|
||||
reddit.rall_url = 'https://www.reddit.com/.json?limit='
|
||||
|
||||
function reddit:action(msg, config)
|
||||
-- Eight results in PM, four results elsewhere.
|
||||
@ -59,7 +56,7 @@ function reddit:action(msg, config)
|
||||
source = '*/' .. utilities.md_escape(input) .. '*\n'
|
||||
else
|
||||
input = utilities.input(msg.text)
|
||||
source = '*Results for* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
||||
source = '*Ergebnisse für* _' .. utilities.md_escape(input) .. '_ *:*\n'
|
||||
input = URL.escape(input)
|
||||
url = reddit.search_url:format(input) .. limit
|
||||
end
|
||||
@ -67,7 +64,7 @@ function reddit:action(msg, config)
|
||||
url = reddit.rall_url .. limit
|
||||
source = '*/r/all*\n'
|
||||
end
|
||||
local jstr, res = HTTP.request(url)
|
||||
local jstr, res = https.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
else
|
55
miku/plugins/reddit_post.lua
Normal file
55
miku/plugins/reddit_post.lua
Normal file
@ -0,0 +1,55 @@
|
||||
local reddit_post = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
reddit_post.triggers = {
|
||||
"reddit.com/r/([A-Za-z0-9-/-_-.]+)/comments/([A-Za-z0-9-/-_-.]+)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'https://www.reddit.com'
|
||||
|
||||
function reddit_post:get_reddit_data(subreddit, reddit_code)
|
||||
local url = BASE_URL..'/r/'..subreddit..'/comments/'..reddit_code..'.json'
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
return data
|
||||
end
|
||||
|
||||
function reddit_post:send_reddit_data(data)
|
||||
local title = utilities.md_escape(data[1].data.children[1].data.title)
|
||||
local author = utilities.md_escape(data[1].data.children[1].data.author)
|
||||
local subreddit = utilities.md_escape(data[1].data.children[1].data.subreddit)
|
||||
if string.len(data[1].data.children[1].data.selftext) > 300 then
|
||||
selftext = string.sub(unescape(data[1].data.children[1].data.selftext:gsub("%b<>", "")), 1, 300) .. '...'
|
||||
else
|
||||
selftext = unescape(data[1].data.children[1].data.selftext:gsub("%b<>", ""))
|
||||
end
|
||||
if not data[1].data.children[1].data.is_self then
|
||||
url = data[1].data.children[1].data.url
|
||||
else
|
||||
url = ''
|
||||
end
|
||||
local score = comma_value(data[1].data.children[1].data.score)
|
||||
local comments = comma_value(data[1].data.children[1].data.num_comments)
|
||||
local text = '*'..author..'* in */r/'..subreddit..'* _('..score..' Upvotes - '..comments..' Kommentare)_:\n'..title..'\n'..selftext..url
|
||||
return text
|
||||
end
|
||||
|
||||
|
||||
function reddit_post:action(msg, config, matches)
|
||||
local subreddit = matches[1]
|
||||
local reddit_code = matches[2]
|
||||
local data = reddit_post:get_reddit_data(subreddit, reddit_code)
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
local text = reddit_post:send_reddit_data(data)
|
||||
if not text then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return reddit_post
|
@ -1,17 +1,15 @@
|
||||
local remind = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
remind.command = 'remind <duration> <message>'
|
||||
remind.command = 'remind <Länge> <Nachricht>'
|
||||
|
||||
function remind:init(config)
|
||||
self.database.reminders = self.database.reminders or {}
|
||||
|
||||
remind.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('remind', true).table
|
||||
remind.doc = [[```
|
||||
]]..config.cmd_pat..[[remind <duration> <message>
|
||||
Repeats a message after a duration of time, in minutes.
|
||||
```]]
|
||||
remind.doc = [[*
|
||||
]]..config.cmd_pat..[[remind* _<Länge>_ _<Nachricht>_: Erinnert dich in X Minuten an die Nachricht]]
|
||||
end
|
||||
|
||||
function remind:action(msg)
|
||||
@ -44,10 +42,10 @@ function remind:action(msg)
|
||||
self.database.reminders[msg.chat.id_str] = self.database.reminders[msg.chat.id_str] or {}
|
||||
-- Limit group reminders to 10 and private reminders to 50.
|
||||
if msg.chat.type ~= 'private' and utilities.table_size(self.database.reminders[msg.chat.id_str]) > 9 then
|
||||
utilities.send_reply(self, msg, 'Sorry, this group already has ten reminders.')
|
||||
utilities.send_reply(self, msg, 'Diese Gruppe hat schon zehn Erinnerungen!')
|
||||
return
|
||||
elseif msg.chat.type == 'private' and utilities.table_size(self.database.reminders[msg.chat.id_str]) > 49 then
|
||||
utilities.send_reply(msg, 'Sorry, you already have fifty reminders.')
|
||||
utilities.send_reply(msg, 'Du hast schon 50 Erinnerungen!')
|
||||
return
|
||||
end
|
||||
-- Put together the reminder with the expiration, message, and message to reply to.
|
||||
@ -56,11 +54,11 @@ function remind:action(msg)
|
||||
message = message
|
||||
}
|
||||
table.insert(self.database.reminders[msg.chat.id_str], reminder)
|
||||
local output = 'I will remind you in ' .. duration
|
||||
local output = 'Ich werde dich in ' .. duration
|
||||
if duration == 1 then
|
||||
output = output .. ' minute!'
|
||||
output = output .. ' Minute erinnern!'
|
||||
else
|
||||
output = output .. ' minutes!'
|
||||
output = output .. ' Minuten erinnern!'
|
||||
end
|
||||
utilities.send_reply(self, msg, output)
|
||||
end
|
||||
@ -75,7 +73,7 @@ function remind:cron()
|
||||
-- If the reminder is past-due, send it and nullify it.
|
||||
-- Otherwise, add it to the replacement table.
|
||||
if time > reminder.time then
|
||||
local output = '*Reminder:*\n"' .. utilities.md_escape(reminder.message) .. '"'
|
||||
local output = '*ERINNERUNG:*\n"' .. utilities.md_escape(reminder.message) .. '"'
|
||||
local res = utilities.send_message(self, chat_id, output, true, nil, true)
|
||||
-- If the message fails to send, save it for later.
|
||||
if not res then
|
||||
@ -94,4 +92,4 @@ function remind:cron()
|
||||
end
|
||||
end
|
||||
|
||||
return remind
|
||||
return remind
|
@ -1,8 +1,8 @@
|
||||
local respond = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local bindings = require('miku.bindings')
|
||||
|
||||
function respond:init(config)
|
||||
respond.triggers = {
|
@ -1,6 +1,6 @@
|
||||
local roll = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
roll.command = 'roll'
|
||||
|
@ -3,19 +3,30 @@ local rss = {}
|
||||
local http = require('socket.http')
|
||||
local https = require('ssl.https')
|
||||
local url = require('socket.url')
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local bindings = require('miku.bindings')
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
local feedparser = require("feedparser")
|
||||
|
||||
rss.command = 'rss <sub/del>'
|
||||
|
||||
function rss:init(config)
|
||||
rss.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('rss', true).table
|
||||
rss.triggers = {
|
||||
"^/(rss) @(.*)$",
|
||||
"^/rss$",
|
||||
"^/rss (sub) (https?://[%w-_%.%?%.:/%+=&%~]+) @(.*)$",
|
||||
"^/rss (sub) (https?://[%w-_%.%?%.:/%+=&%~]+)$",
|
||||
"^/rss (del) (%d+) @(.*)$",
|
||||
"^/rss (del) (%d+)$",
|
||||
"^/rss (del)",
|
||||
"^/rss (sync)$"
|
||||
}
|
||||
rss.doc = [[*
|
||||
]]..config.cmd_pat..[[rss*: Feed-Abonnements anzeigen
|
||||
*]]..config.cmd_pat..[[rss* _sub_ _<URL>_: Diesen Feed abonnieren
|
||||
*]]..config.cmd_pat..[[rss* _del_ _<#>_: Diesen Feed deabonnieren
|
||||
*]]..config.cmd_pat..[[rss* _sync_: Feeds syncen (nur Superuser)]]
|
||||
]]..config.cmd_pat..[[rss* _@[Kanalname]_: Feed-Abonnements anzeigen
|
||||
*]]..config.cmd_pat..[[rss* _sub_ _<URL>_ _@[Kanalname]_: Diesen Feed abonnieren
|
||||
*]]..config.cmd_pat..[[rss* _del_ _<#>_ _@[Kanalname]_: Diesen Feed deabonnieren
|
||||
*]]..config.cmd_pat..[[rss* _sync_: Feeds syncen (nur Superuser)
|
||||
Der Kanalname ist optional]]
|
||||
end
|
||||
|
||||
function tail(n, k)
|
||||
@ -193,58 +204,106 @@ function rss:print_subs(id, chat_name)
|
||||
if not subs[1] then
|
||||
return 'Keine Feeds abonniert!'
|
||||
end
|
||||
local keyboard = '{"keyboard":[['
|
||||
local keyboard_buttons = ''
|
||||
local text = '*'..chat_name..'* hat abonniert:\n---------\n'
|
||||
for k,v in pairs(subs) do
|
||||
text = text .. k .. ") " .. v .. '\n'
|
||||
if k == #subs then
|
||||
keyboard_buttons = keyboard_buttons..'{"text":"/rss del '..k..'"}'
|
||||
break;
|
||||
end
|
||||
keyboard_buttons = keyboard_buttons..'{"text":"/rss del '..k..'"},'
|
||||
end
|
||||
return text
|
||||
local keyboard = keyboard..keyboard_buttons..']], "one_time_keyboard":true, "selective":true, "resize_keyboard":true}'
|
||||
return text, keyboard
|
||||
end
|
||||
|
||||
function rss:action(msg, config)
|
||||
local input = utilities.input(msg.text)
|
||||
function rss:action(msg, config, matches)
|
||||
local id = "user#id" .. msg.from.id
|
||||
if msg.chat.type == 'channel' then
|
||||
print('Kanäle werden momentan nicht unterstützt')
|
||||
end
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
id = 'chat#id'..msg.chat.id
|
||||
end
|
||||
|
||||
if not input then
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
chat_name = msg.chat.title
|
||||
else
|
||||
chat_name = msg.chat.first_name
|
||||
-- For channels
|
||||
if matches[1] == 'sub' and matches[2] and matches[3] then
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
local id = '@'..matches[3]
|
||||
local result = utilities.get_chat_info(self, id)
|
||||
if not result then
|
||||
utilities.send_reply(self, msg, 'Diesen Kanal gibt es nicht!')
|
||||
return
|
||||
end
|
||||
local output = rss:subscribe(id, matches[2])
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
return
|
||||
elseif matches[1] == 'del' and matches[2] and matches[3] then
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
local id = '@'..matches[3]
|
||||
local result = utilities.get_chat_info(self, id)
|
||||
if not result then
|
||||
utilities.send_reply(self, msg, 'Diesen Kanal gibt es nicht!')
|
||||
return
|
||||
end
|
||||
local output = rss:unsubscribe(id, matches[2])
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
return
|
||||
elseif matches[1] == 'rss' and matches[2] then
|
||||
local id = '@'..matches[2]
|
||||
local result = utilities.get_chat_info(self, id)
|
||||
if not result then
|
||||
utilities.send_reply(self, msg, 'Diesen Kanal gibt es nicht!')
|
||||
return
|
||||
end
|
||||
local chat_name = result.result.title
|
||||
local output = rss:print_subs(id, chat_name)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
return
|
||||
end
|
||||
|
||||
if input:match('(sub) (https?://[%w-_%.%?%.:/%+=&%~]+)$') then
|
||||
|
||||
if msg.chat.type == 'group' or msg.chat.type == 'supergroup' then
|
||||
chat_name = msg.chat.title
|
||||
else
|
||||
chat_name = msg.chat.first_name
|
||||
end
|
||||
|
||||
if matches[1] == 'sub' and matches[2] then
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
local rss_url = input:match('(https?://[%w-_%.%?%.:/%+=&%~]+)$')
|
||||
local output = rss:subscribe(id, rss_url)
|
||||
local output = rss:subscribe(id, matches[2])
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
elseif input:match('(del) (%d+)$') then
|
||||
return
|
||||
elseif matches[1] == 'del' and matches[2] then
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
local rss_url = input:match('(%d+)$')
|
||||
local output = rss:unsubscribe(id, rss_url)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
elseif input:match('(sync)$') then
|
||||
local output = rss:unsubscribe(id, matches[2])
|
||||
utilities.send_reply(self, msg, output, true, '{"hide_keyboard":true}')
|
||||
return
|
||||
elseif matches[1] == 'del' and not matches[2] then
|
||||
local list_subs, keyboard = rss:print_subs(id, chat_name)
|
||||
utilities.send_reply(self, msg, list_subs, true, keyboard)
|
||||
return
|
||||
elseif matches[1] == 'sync' then
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
rss:cron(self)
|
||||
return
|
||||
end
|
||||
|
||||
local output = rss:print_subs(id, chat_name)
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
return
|
||||
end
|
||||
|
||||
@ -285,7 +344,7 @@ function rss:cron(self_plz)
|
||||
else
|
||||
content = ''
|
||||
end
|
||||
text = text..'\n*'..title..'*\n'..content..' [Weiterlesen]('..link..')\n'
|
||||
text = text..'\n[[#RSS]] *'..title..'*\n'..utilities.trim(utilities.markdown_escape_simple(content))..' [Weiterlesen]('..link..')\n'
|
||||
end
|
||||
if text ~= '' then
|
||||
local newlast = newentr[1].id
|
||||
@ -299,4 +358,4 @@ function rss:cron(self_plz)
|
||||
end
|
||||
end
|
||||
|
||||
return rss
|
||||
return rss
|
@ -1,7 +1,7 @@
|
||||
local set = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
local utilities = require('miku.utilities')
|
||||
local redis = (loadfile "./miku/redis.lua")()
|
||||
|
||||
set.command = 'set <Variable> <Wert>'
|
||||
|
||||
@ -35,7 +35,7 @@ end
|
||||
|
||||
function set:action(msg)
|
||||
local input = utilities.input(msg.text)
|
||||
if not input:match('([^%s]+) (.+)') then
|
||||
if not input or not input:match('([^%s]+) (.+)') then
|
||||
utilities.send_message(self, msg.chat.id, set.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
local shell = {}
|
||||
|
||||
local utilities = require('otouto.utilities')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function shell:init(config)
|
||||
shell.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('sh', true).table
|
||||
@ -10,6 +10,7 @@ function shell:action(msg, config)
|
||||
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
return
|
||||
end
|
||||
|
||||
local input = utilities.input(msg.text)
|
28
miku/plugins/site_header.lua
Normal file
28
miku/plugins/site_header.lua
Normal file
@ -0,0 +1,28 @@
|
||||
local site_header = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
function site_header:init(config)
|
||||
site_header.triggers = {
|
||||
"^/(head) ([%w-_%.%?%.:,/%+=&#!]+)$",
|
||||
"^/(dig) ([%w-_%.%?%.:,/%+=&#!]+)$"
|
||||
}
|
||||
end
|
||||
|
||||
function site_header:action(msg, config, matches)
|
||||
if msg.from.id ~= config.admin then
|
||||
utilities.send_reply(self, msg, config.errors.sudo)
|
||||
end
|
||||
|
||||
local url = matches[2]
|
||||
if matches[1] == 'head' then
|
||||
input = 'curl --head '..url
|
||||
elseif matches[1] == 'dig' then
|
||||
input = 'dig '..url..' ANY'
|
||||
end
|
||||
local output = io.popen(input):read('*all')
|
||||
output = '```\n' .. output .. '\n```'
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
end
|
||||
|
||||
return site_header
|
41
miku/plugins/soundcloud.lua
Normal file
41
miku/plugins/soundcloud.lua
Normal file
@ -0,0 +1,41 @@
|
||||
local soundcloud = {}
|
||||
|
||||
local http = require('socket.http')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
soundcloud.triggers = {
|
||||
"soundcloud.com/([A-Za-z0-9-/-_-.]+)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'http://api.soundcloud.com/resolve.json'
|
||||
local client_id = cred_data.soundcloud_client_id
|
||||
|
||||
function soundcloud:send_soundcloud_info(sc_url)
|
||||
local url = BASE_URL..'?url=http://soundcloud.com/'..sc_url..'&client_id='..client_id
|
||||
|
||||
local res,code = http.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
|
||||
local title = data.title
|
||||
local description = data.description
|
||||
local user = data.user.username
|
||||
local user = 'Unbekannt'
|
||||
local genre = data.genre
|
||||
local playback_count = data.playback_count
|
||||
local milliseconds = data.duration
|
||||
local totalseconds = math.floor(milliseconds / 1000)
|
||||
local duration = makeHumanTime(totalseconds)
|
||||
|
||||
local text = '*'..title..'* von _'..user..'_\n_(Tag: '..genre..', '..duration..'; '..playback_count..' mal angehört)_\n'..description
|
||||
return text
|
||||
end
|
||||
|
||||
function soundcloud:action(msg, config, matches)
|
||||
local text = soundcloud:send_soundcloud_info(matches[1])
|
||||
if not text then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return soundcloud
|
17
miku/plugins/speedtest.lua
Normal file
17
miku/plugins/speedtest.lua
Normal file
@ -0,0 +1,17 @@
|
||||
local speedtest = {}
|
||||
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
speedtest.triggers = {
|
||||
"speedtest.net/my%-result/(%d+)",
|
||||
"speedtest.net/my%-result/i/(%d+)"
|
||||
}
|
||||
|
||||
function speedtest:action(msg, config, matches)
|
||||
local url = 'http://www.speedtest.net/result/'..matches[1]..'.png'
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_photo')
|
||||
local file = download_to_file(url)
|
||||
utilities.send_photo(self, msg.chat.id, file, nil, msg.message_id)
|
||||
end
|
||||
|
||||
return speedtest
|
52
miku/plugins/spotify.lua
Normal file
52
miku/plugins/spotify.lua
Normal file
@ -0,0 +1,52 @@
|
||||
local spotify = {}
|
||||
|
||||
local https = require('ssl.https')
|
||||
local json = require('dkjson')
|
||||
local utilities = require('miku.utilities')
|
||||
|
||||
spotify.triggers = {
|
||||
"open.spotify.com/track/([A-Za-z0-9-]+)",
|
||||
"play.spotify.com/track/([A-Za-z0-9-]+)"
|
||||
}
|
||||
|
||||
local BASE_URL = 'https://api.spotify.com/v1'
|
||||
|
||||
function spotify:get_track_data(track)
|
||||
local url = BASE_URL..'/tracks/'..track
|
||||
local res,code = https.request(url)
|
||||
if code ~= 200 then return nil end
|
||||
local data = json.decode(res)
|
||||
return data
|
||||
end
|
||||
|
||||
function spotify:send_track_data(data, self, msg)
|
||||
local name = data.name
|
||||
local album = data.album.name
|
||||
local artist = data.artists[1].name
|
||||
local preview = data.preview_url
|
||||
local milliseconds = data.duration_ms
|
||||
|
||||
-- convert s to mm:ss
|
||||
local totalseconds = math.floor(milliseconds / 1000)
|
||||
local duration = makeHumanTime(totalseconds)
|
||||
|
||||
local text = '*'..name..'* von *'..artist..'* aus dem Album *'..album..'* _('..duration..')_'
|
||||
if preview then
|
||||
utilities.send_typing(self, msg.chat.id, 'upload_audio')
|
||||
local file = download_to_file(preview, name..'.mp3')
|
||||
utilities.send_audio(self, msg.chat.id, file, msg.message_id, totalseconds, artist, name)
|
||||
return
|
||||
else
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function spotify:action(msg, config, matches)
|
||||
local data = spotify:get_track_data(matches[1])
|
||||
if not data then utilities.send_reply(self, msg, config.errors.connection) return end
|
||||
spotify:send_track_data(data, self, msg)
|
||||
return
|
||||
end
|
||||
|
||||
return spotify
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user