change focus from bot to just bindings, code cleanup

pull/1/head
Syfaro 10 years ago
parent 5d6f84e9b2
commit 9cf4f13772
  1. 52
      README.md
  2. 131
      bot.go
  3. 144
      helpers.go
  4. 429
      methods.go
  5. 99
      plugin_fa.go
  6. 76
      plugin_help.go
  7. 153
      plugin_manage.go
  8. 2
      types.go
  9. 22
      updates.go

@ -1,54 +1,6 @@
# Golang Telegram bot using the Bot API
A simple Golang bot for the Telegram Bot API
# Golang Telegram bindings for the Bot API
Really simple bot for interacting with the Telegram Bot API, not nearly done yet. Expect frequent breaking changes!
Bindings for interacting with the Telegram Bot API, not nearly done yet.
All methods have been added, and all features should be available.
If you want a feature that hasn't been added yet, open an issue and I'll see what I can do.
There's a few plugins in here, named as `plugin_*.go`.
## Getting started
After installing all the dependencies, run
```
go build
./telegram-bot-api -newbot
```
Fill in any asked information, enable whatever plugins, etc.
## Plugins
All plugins implement the `Plugin` interface.
```go
type Plugin interface {
GetName() string
GetCommands() []string
GetHelpText() []string
GotCommand(string, Message, []string)
Setup()
}
```
`GetName` should return the plugin's name. This must be unique!
`GetCommands` should return a slice of strings, each command should look like `/help`, it must have the forward slash!
`GetHelpText` should return a slice of strings with each command and usage. You many include any number of items in here.
`GotCommand` is called when a command is executed for this plugin, the parameters are the command name, the Message struct, and a list of arguments passed to the command. The original text is available in the Message struct.
`Setup` is called when the bot first starts, if it needs any configuration, ask here.
To add your plugin, you must edit a line of code and then run the `go build` again.
```go
// current version
plugins = []Plugin{&HelpPlugin{}, &ManagePlugin{}}
// add your own plugins
plugins = []Plugin{&HelpPlugin{}, &FAPlugin{}, &ManagePlugin{}}
```

131
bot.go

@ -1,128 +1,13 @@
package main
package tgbotapi
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"strings"
"time"
)
type Config struct {
Token string `json:"token"`
Plugins map[string]string `json:"plugins"`
EnabledPlugins map[string]bool `json:"enabled"`
}
type Plugin interface {
GetName() string
GetCommands() []string
GetHelpText() []string
GotCommand(string, Message, []string)
Setup()
type BotApi struct {
Token string `json:"token"`
Debug bool `json:"debug"`
Updates chan Update `json:"-"`
}
var bot *BotApi
var plugins []Plugin
var config Config
var configPath *string
func main() {
configPath = flag.String("config", "config.json", "path to config.json")
flag.Parse()
data, err := ioutil.ReadFile(*configPath)
if err != nil {
log.Panic(err)
}
json.Unmarshal(data, &config)
bot = NewBotApi(BotConfig{
token: config.Token,
debug: true,
})
plugins = []Plugin{&HelpPlugin{}, &FAPlugin{}, &ManagePlugin{}}
for _, plugin := range plugins {
val, ok := config.EnabledPlugins[plugin.GetName()]
if !ok {
fmt.Printf("Enable '%s'? [y/N] ", plugin.GetName())
var enabled string
fmt.Scanln(&enabled)
if strings.ToLower(enabled) == "y" {
plugin.Setup()
log.Printf("Plugin '%s' started!\n", plugin.GetName())
config.EnabledPlugins[plugin.GetName()] = true
} else {
config.EnabledPlugins[plugin.GetName()] = false
}
}
if val {
plugin.Setup()
log.Printf("Plugin '%s' started!\n", plugin.GetName())
}
saveConfig()
func NewBotApi(token string) *BotApi {
return &BotApi{
Token: token,
}
ticker := time.NewTicker(time.Second)
lastUpdate := 0
for range ticker.C {
update := NewUpdate(lastUpdate + 1)
update.Timeout = 30
updates, err := bot.getUpdates(update)
if err != nil {
log.Panic(err)
}
for _, update := range updates {
lastUpdate = update.UpdateId
if update.Message.Text == "" {
continue
}
for _, plugin := range plugins {
val, _ := config.EnabledPlugins[plugin.GetName()]
if !val {
continue
}
parts := strings.Split(update.Message.Text, " ")
command := parts[0]
for _, cmd := range plugin.GetCommands() {
if cmd == command {
if bot.config.debug {
log.Printf("'%s' matched plugin '%s'", update.Message.Text, plugin.GetName())
}
args := append(parts[:0], parts[1:]...)
plugin.GotCommand(command, update.Message, args)
}
}
}
}
}
}
func saveConfig() {
data, _ := json.MarshalIndent(config, "", " ")
ioutil.WriteFile(*configPath, data, 0600)
}

@ -0,0 +1,144 @@
package tgbotapi
import (
"net/url"
)
func NewMessage(chatId int, text string) MessageConfig {
return MessageConfig{
ChatId: chatId,
Text: text,
DisableWebPagePreview: false,
ReplyToMessageId: 0,
}
}
func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
return ForwardConfig{
ChatId: chatId,
FromChatId: fromChatId,
MessageId: messageId,
}
}
func NewPhotoUpload(chatId int, filename string) PhotoConfig {
return PhotoConfig{
ChatId: chatId,
UseExistingPhoto: false,
FilePath: filename,
}
}
func NewPhotoShare(chatId int, fileId string) PhotoConfig {
return PhotoConfig{
ChatId: chatId,
UseExistingPhoto: true,
FileId: fileId,
}
}
func NewAudioUpload(chatId int, filename string) AudioConfig {
return AudioConfig{
ChatId: chatId,
UseExistingAudio: false,
FilePath: filename,
}
}
func NewAudioShare(chatId int, fileId string) AudioConfig {
return AudioConfig{
ChatId: chatId,
UseExistingAudio: true,
FileId: fileId,
}
}
func NewDocumentUpload(chatId int, filename string) DocumentConfig {
return DocumentConfig{
ChatId: chatId,
UseExistingDocument: false,
FilePath: filename,
}
}
func NewDocumentShare(chatId int, fileId string) DocumentConfig {
return DocumentConfig{
ChatId: chatId,
UseExistingDocument: true,
FileId: fileId,
}
}
func NewStickerUpload(chatId int, filename string) StickerConfig {
return StickerConfig{
ChatId: chatId,
UseExistingSticker: false,
FilePath: filename,
}
}
func NewStickerShare(chatId int, fileId string) StickerConfig {
return StickerConfig{
ChatId: chatId,
UseExistingSticker: true,
FileId: fileId,
}
}
func NewVideoUpload(chatId int, filename string) VideoConfig {
return VideoConfig{
ChatId: chatId,
UseExistingVideo: false,
FilePath: filename,
}
}
func NewVideoShare(chatId int, fileId string) VideoConfig {
return VideoConfig{
ChatId: chatId,
UseExistingVideo: true,
FileId: fileId,
}
}
func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
return LocationConfig{
ChatId: chatId,
Latitude: latitude,
Longitude: longitude,
ReplyToMessageId: 0,
ReplyMarkup: nil,
}
}
func NewChatAction(chatId int, action string) ChatActionConfig {
return ChatActionConfig{
ChatId: chatId,
Action: action,
}
}
func NewUserProfilePhotos(userId int) UserProfilePhotosConfig {
return UserProfilePhotosConfig{
UserId: userId,
Offset: 0,
Limit: 0,
}
}
func NewUpdate(offset int) UpdateConfig {
return UpdateConfig{
Offset: offset,
Limit: 0,
Timeout: 0,
}
}
func NewWebhook(link string) WebhookConfig {
u, _ := url.Parse(link)
return WebhookConfig{
Url: u,
Clear: false,
}
}

@ -1,4 +1,4 @@
package main
package tgbotapi
import (
"bytes"
@ -25,23 +25,98 @@ const (
CHAT_FIND_LOCATION = "find_location"
)
type BotConfig struct {
token string
debug bool
type MessageConfig struct {
ChatId int
Text string
DisableWebPagePreview bool
ReplyToMessageId int
ReplyMarkup interface{}
}
type BotApi struct {
config BotConfig
type ForwardConfig struct {
ChatId int
FromChatId int
MessageId int
}
func NewBotApi(config BotConfig) *BotApi {
return &BotApi{
config: config,
}
type PhotoConfig struct {
ChatId int
Caption string
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingPhoto bool
FilePath string
FileId string
}
type AudioConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingAudio bool
FilePath string
FileId string
}
type DocumentConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingDocument bool
FilePath string
FileId string
}
type StickerConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingSticker bool
FilePath string
FileId string
}
type VideoConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingVideo bool
FilePath string
FileId string
}
type LocationConfig struct {
ChatId int
Latitude float64
Longitude float64
ReplyToMessageId int
ReplyMarkup interface{}
}
type ChatActionConfig struct {
ChatId int
Action string
}
type UserProfilePhotosConfig struct {
UserId int
Offset int
Limit int
}
type UpdateConfig struct {
Offset int
Limit int
Timeout int
}
type WebhookConfig struct {
Clear bool
Url *url.URL
}
func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse, error) {
resp, err := http.PostForm("https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, params)
func (bot *BotApi) MakeRequest(endpoint string, params url.Values) (ApiResponse, error) {
resp, err := http.PostForm("https://api.telegram.org/bot"+bot.Token+"/"+endpoint, params)
defer resp.Body.Close()
if err != nil {
return ApiResponse{}, err
@ -52,7 +127,7 @@ func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse,
return ApiResponse{}, err
}
if bot.config.debug {
if bot.Debug {
log.Println(endpoint, string(bytes))
}
@ -66,7 +141,7 @@ func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse,
return apiResp, nil
}
func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) {
func (bot *BotApi) UploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) {
var b bytes.Buffer
w := multipart.NewWriter(&b)
@ -96,7 +171,7 @@ func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldna
w.Close()
req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, &b)
req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.Token+"/"+endpoint, &b)
if err != nil {
return ApiResponse{}, err
}
@ -114,7 +189,7 @@ func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldna
return ApiResponse{}, err
}
if bot.config.debug {
if bot.Debug {
log.Println(string(bytes[:]))
}
@ -124,8 +199,8 @@ func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldna
return apiResp, nil
}
func (bot *BotApi) getMe() (User, error) {
resp, err := bot.makeRequest("getMe", nil)
func (bot *BotApi) GetMe() (User, error) {
resp, err := bot.MakeRequest("getMe", nil)
if err != nil {
return User{}, err
}
@ -133,14 +208,14 @@ func (bot *BotApi) getMe() (User, error) {
var user User
json.Unmarshal(resp.Result, &user)
if bot.config.debug {
if bot.Debug {
log.Printf("getMe: %+v\n", user)
}
return user, nil
}
func (bot *BotApi) sendMessage(config MessageConfig) (Message, error) {
func (bot *BotApi) SendMessage(config MessageConfig) (Message, error) {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
v.Add("text", config.Text)
@ -157,7 +232,7 @@ func (bot *BotApi) sendMessage(config MessageConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendMessage", v)
resp, err := bot.MakeRequest("SendMessage", v)
if err != nil {
return Message{}, err
}
@ -165,21 +240,21 @@ func (bot *BotApi) sendMessage(config MessageConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
log.Printf("sendMessage req : %+v\n", v)
log.Printf("sendMessage resp: %+v\n", message)
if bot.Debug {
log.Printf("SendMessage req : %+v\n", v)
log.Printf("SendMessage resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) {
func (bot *BotApi) ForwardMessage(config ForwardConfig) (Message, error) {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
v.Add("from_chat_id", strconv.Itoa(config.FromChatId))
v.Add("message_id", strconv.Itoa(config.MessageId))
resp, err := bot.makeRequest("forwardMessage", v)
resp, err := bot.MakeRequest("forwardMessage", v)
if err != nil {
return Message{}, err
}
@ -187,7 +262,7 @@ func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("forwardMessage req : %+v\n", v)
log.Printf("forwardMessage resp: %+v\n", message)
}
@ -195,7 +270,7 @@ func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) {
return message, nil
}
func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
func (bot *BotApi) SendPhoto(config PhotoConfig) (Message, error) {
if config.UseExistingPhoto {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -215,7 +290,7 @@ func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendPhoto", v)
resp, err := bot.MakeRequest("SendPhoto", v)
if err != nil {
return Message{}, err
}
@ -223,9 +298,9 @@ func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
log.Printf("sendPhoto req : %+v\n", v)
log.Printf("sendPhoto resp: %+v\n", message)
if bot.Debug {
log.Printf("SendPhoto req : %+v\n", v)
log.Printf("SendPhoto resp: %+v\n", message)
}
return message, nil
@ -248,7 +323,7 @@ func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
params["reply_markup"] = string(data)
}
resp, err := bot.uploadFile("sendPhoto", params, "photo", config.FilePath)
resp, err := bot.UploadFile("SendPhoto", params, "photo", config.FilePath)
if err != nil {
return Message{}, err
}
@ -256,14 +331,14 @@ func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
log.Printf("sendPhoto resp: %+v\n", message)
if bot.Debug {
log.Printf("SendPhoto resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
func (bot *BotApi) SendAudio(config AudioConfig) (Message, error) {
if config.UseExistingAudio {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -280,7 +355,7 @@ func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendAudio", v)
resp, err := bot.MakeRequest("sendAudio", v)
if err != nil {
return Message{}, err
}
@ -288,7 +363,7 @@ func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendAudio req : %+v\n", v)
log.Printf("sendAudio resp: %+v\n", message)
}
@ -311,7 +386,7 @@ func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
params["reply_markup"] = string(data)
}
resp, err := bot.uploadFile("sendAudio", params, "audio", config.FilePath)
resp, err := bot.UploadFile("sendAudio", params, "audio", config.FilePath)
if err != nil {
return Message{}, err
}
@ -319,14 +394,14 @@ func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendAudio resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
func (bot *BotApi) SendDocument(config DocumentConfig) (Message, error) {
if config.UseExistingDocument {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -343,7 +418,7 @@ func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendDocument", v)
resp, err := bot.MakeRequest("sendDocument", v)
if err != nil {
return Message{}, err
}
@ -351,7 +426,7 @@ func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendDocument req : %+v\n", v)
log.Printf("sendDocument resp: %+v\n", message)
}
@ -374,7 +449,7 @@ func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
params["reply_markup"] = string(data)
}
resp, err := bot.uploadFile("sendDocument", params, "document", config.FilePath)
resp, err := bot.UploadFile("sendDocument", params, "document", config.FilePath)
if err != nil {
return Message{}, err
}
@ -382,14 +457,14 @@ func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendDocument resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
func (bot *BotApi) SendSticker(config StickerConfig) (Message, error) {
if config.UseExistingSticker {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -406,7 +481,7 @@ func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendSticker", v)
resp, err := bot.MakeRequest("sendSticker", v)
if err != nil {
return Message{}, err
}
@ -414,7 +489,7 @@ func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendSticker req : %+v\n", v)
log.Printf("sendSticker resp: %+v\n", message)
}
@ -437,7 +512,7 @@ func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
params["reply_markup"] = string(data)
}
resp, err := bot.uploadFile("sendSticker", params, "sticker", config.FilePath)
resp, err := bot.UploadFile("sendSticker", params, "sticker", config.FilePath)
if err != nil {
return Message{}, err
}
@ -445,14 +520,14 @@ func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendSticker resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
func (bot *BotApi) SendVideo(config VideoConfig) (Message, error) {
if config.UseExistingVideo {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -469,7 +544,7 @@ func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendVideo", v)
resp, err := bot.MakeRequest("sendVideo", v)
if err != nil {
return Message{}, err
}
@ -477,7 +552,7 @@ func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendVideo req : %+v\n", v)
log.Printf("sendVideo resp: %+v\n", message)
}
@ -500,7 +575,7 @@ func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
params["reply_markup"] = string(data)
}
resp, err := bot.uploadFile("sendVideo", params, "video", config.FilePath)
resp, err := bot.UploadFile("sendVideo", params, "video", config.FilePath)
if err != nil {
return Message{}, err
}
@ -508,14 +583,14 @@ func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendVideo resp: %+v\n", message)
}
return message, nil
}
func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
func (bot *BotApi) SendLocation(config LocationConfig) (Message, error) {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
@ -532,7 +607,7 @@ func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
v.Add("reply_markup", string(data))
}
resp, err := bot.makeRequest("sendLocation", v)
resp, err := bot.MakeRequest("sendLocation", v)
if err != nil {
return Message{}, err
}
@ -540,7 +615,7 @@ func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
var message Message
json.Unmarshal(resp.Result, &message)
if bot.config.debug {
if bot.Debug {
log.Printf("sendLocation req : %+v\n", v)
log.Printf("sendLocation resp: %+v\n", message)
}
@ -548,12 +623,12 @@ func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) {
return message, nil
}
func (bot *BotApi) sendChatAction(config ChatActionConfig) error {
func (bot *BotApi) SendChatAction(config ChatActionConfig) error {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
v.Add("action", config.Action)
_, err := bot.makeRequest("sendChatAction", v)
_, err := bot.MakeRequest("sendChatAction", v)
if err != nil {
return err
}
@ -561,7 +636,7 @@ func (bot *BotApi) sendChatAction(config ChatActionConfig) error {
return nil
}
func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
func (bot *BotApi) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
v := url.Values{}
v.Add("user_id", strconv.Itoa(config.UserId))
if config.Offset != 0 {
@ -571,7 +646,7 @@ func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
v.Add("limit", strconv.Itoa(config.Limit))
}
resp, err := bot.makeRequest("getUserProfilePhotos", v)
resp, err := bot.MakeRequest("getUserProfilePhotos", v)
if err != nil {
return UserProfilePhotos{}, err
}
@ -579,7 +654,7 @@ func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
var profilePhotos UserProfilePhotos
json.Unmarshal(resp.Result, &profilePhotos)
if bot.config.debug {
if bot.Debug {
log.Printf("getUserProfilePhotos req : %+v\n", v)
log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos)
}
@ -587,7 +662,7 @@ func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
return profilePhotos, nil
}
func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
func (bot *BotApi) GetUpdates(config UpdateConfig) ([]Update, error) {
v := url.Values{}
if config.Offset > 0 {
v.Add("offset", strconv.Itoa(config.Offset))
@ -599,7 +674,7 @@ func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
v.Add("timeout", strconv.Itoa(config.Timeout))
}
resp, err := bot.makeRequest("getUpdates", v)
resp, err := bot.MakeRequest("getUpdates", v)
if err != nil {
return []Update{}, err
}
@ -607,230 +682,20 @@ func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) {
var updates []Update
json.Unmarshal(resp.Result, &updates)
if bot.config.debug {
if bot.Debug {
log.Printf("getUpdates: %+v\n", updates)
}
return updates, nil
}
func (bot *BotApi) setWebhook(v url.Values) error {
_, err := bot.makeRequest("setWebhook", v)
return err
}
type UpdateConfig struct {
Offset int
Limit int
Timeout int
}
type MessageConfig struct {
ChatId int
Text string
DisableWebPagePreview bool
ReplyToMessageId int
ReplyMarkup interface{}
}
type ForwardConfig struct {
ChatId int
FromChatId int
MessageId int
}
type PhotoConfig struct {
ChatId int
Caption string
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingPhoto bool
FilePath string
FileId string
}
type AudioConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingAudio bool
FilePath string
FileId string
}
type DocumentConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingDocument bool
FilePath string
FileId string
}
type StickerConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingSticker bool
FilePath string
FileId string
}
type VideoConfig struct {
ChatId int
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingVideo bool
FilePath string
FileId string
}
type LocationConfig struct {
ChatId int
Latitude float64
Longitude float64
ReplyToMessageId int
ReplyMarkup interface{}
}
type ChatActionConfig struct {
ChatId int
Action string
}
type UserProfilePhotosConfig struct {
UserId int
Offset int
Limit int
}
func NewMessage(chatId int, text string) MessageConfig {
return MessageConfig{
ChatId: chatId,
Text: text,
DisableWebPagePreview: false,
ReplyToMessageId: 0,
}
}
func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
return ForwardConfig{
ChatId: chatId,
FromChatId: fromChatId,
MessageId: messageId,
}
}
func NewPhotoUpload(chatId int, filename string) PhotoConfig {
return PhotoConfig{
ChatId: chatId,
UseExistingPhoto: false,
FilePath: filename,
}
}
func NewPhotoShare(chatId int, fileId string) PhotoConfig {
return PhotoConfig{
ChatId: chatId,
UseExistingPhoto: true,
FileId: fileId,
}
}
func NewAudioUpload(chatId int, filename string) AudioConfig {
return AudioConfig{
ChatId: chatId,
UseExistingAudio: false,
FilePath: filename,
}
}
func NewAudioShare(chatId int, fileId string) AudioConfig {
return AudioConfig{
ChatId: chatId,
UseExistingAudio: true,
FileId: fileId,
}
}
func NewDocumentUpload(chatId int, filename string) DocumentConfig {
return DocumentConfig{
ChatId: chatId,
UseExistingDocument: false,
FilePath: filename,
}
}
func NewDocumentShare(chatId int, fileId string) DocumentConfig {
return DocumentConfig{
ChatId: chatId,
UseExistingDocument: true,
FileId: fileId,
}
}
func NewStickerUpload(chatId int, filename string) StickerConfig {
return StickerConfig{
ChatId: chatId,
UseExistingSticker: false,
FilePath: filename,
}
}
func NewStickerShare(chatId int, fileId string) StickerConfig {
return StickerConfig{
ChatId: chatId,
UseExistingSticker: true,
FileId: fileId,
}
}
func NewVideoUpload(chatId int, filename string) VideoConfig {
return VideoConfig{
ChatId: chatId,
UseExistingVideo: false,
FilePath: filename,
}
}
func NewVideoShare(chatId int, fileId string) VideoConfig {
return VideoConfig{
ChatId: chatId,
UseExistingVideo: true,
FileId: fileId,
}
}
func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
return LocationConfig{
ChatId: chatId,
Latitude: latitude,
Longitude: longitude,
ReplyToMessageId: 0,
ReplyMarkup: nil,
}
}
func NewChatAction(chatId int, action string) ChatActionConfig {
return ChatActionConfig{
ChatId: chatId,
Action: action,
func (bot *BotApi) SetWebhook(config WebhookConfig) error {
v := url.Values{}
if !config.Clear {
v.Add("url", config.Url.String())
}
}
func NewUserProfilePhotos(userId int) UserProfilePhotosConfig {
return UserProfilePhotosConfig{
UserId: userId,
Offset: 0,
Limit: 0,
}
}
_, err := bot.MakeRequest("setWebhook", v)
func NewUpdate(offset int) UpdateConfig {
return UpdateConfig{
Offset: offset,
Limit: 0,
Timeout: 0,
}
return err
}

@ -1,99 +0,0 @@
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"github.com/ddliu/go-httpclient"
"io"
"net/http"
"os"
"strconv"
"strings"
)
type FAPlugin struct {
}
func (plugin *FAPlugin) GetName() string {
return "FA Mirrorer"
}
func (plugin *FAPlugin) GetCommands() []string {
return []string{"/fa"}
}
func (plugin *FAPlugin) GetHelpText() []string {
return []string{"/fa [link] - mirrors an image from FurAffinity"}
}
func (plugin *FAPlugin) Setup() {
a, ok := config.Plugins["fa_a"]
if !ok {
fmt.Print("FurAffinity Cookie a: ")
fmt.Scanln(&a)
config.Plugins["fa_a"] = a
}
b, ok := config.Plugins["fa_b"]
if !ok {
fmt.Print("FurAffinity Cookie b: ")
fmt.Scanln(&b)
config.Plugins["fa_b"] = b
}
}
func (plugin *FAPlugin) GotCommand(command string, message Message, args []string) {
if len(args) == 0 {
bot.sendMessage(NewMessage(message.Chat.Id, "You need to include a link!"))
return
}
bot.sendChatAction(NewChatAction(message.Chat.Id, CHAT_UPLOAD_PHOTO))
_, err := strconv.Atoi(args[0])
if err == nil {
args[0] = "http://www.furaffinity.net/view/" + args[0]
}
resp, err := httpclient.WithCookie(&http.Cookie{
Name: "b",
Value: config.Plugins["fa_b"],
}).WithCookie(&http.Cookie{
Name: "a",
Value: config.Plugins["fa_a"],
}).Get(args[0], nil)
if err != nil {
bot.sendMessage(NewMessage(message.Chat.Id, "ERR : "+err.Error()))
}
defer resp.Body.Close()
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
bot.sendMessage(NewMessage(message.Chat.Id, "ERR : "+err.Error()))
}
sel := doc.Find("#submissionImg")
for i := range sel.Nodes {
single := sel.Eq(i)
val, _ := single.Attr("src")
tokens := strings.Split(val, "/")
fileName := tokens[len(tokens)-1]
output, _ := os.Create(fileName)
defer output.Close()
defer os.Remove(output.Name())
resp, _ := http.Get("http:" + val)
defer resp.Body.Close()
io.Copy(output, resp.Body)
bot.sendPhoto(NewPhotoUpload(message.Chat.Id, output.Name()))
}
}

@ -1,76 +0,0 @@
package main
import (
"bytes"
"log"
)
type HelpPlugin struct {
}
func (plugin *HelpPlugin) GetName() string {
return "Plugins help"
}
func (plugin *HelpPlugin) GetCommands() []string {
return []string{"/help"}
}
func (plugin *HelpPlugin) GetHelpText() []string {
return []string{"/help (/command) - returns help about a command"}
}
func (plugin *HelpPlugin) Setup() {
}
func (plugin *HelpPlugin) GotCommand(command string, message Message, args []string) {
msg := NewMessage(message.Chat.Id, "")
msg.ReplyToMessageId = message.MessageId
msg.DisableWebPagePreview = true
var buffer bytes.Buffer
if len(args) > 0 {
for _, plug := range plugins {
for _, cmd := range plug.GetCommands() {
log.Println(cmd)
log.Println(args[0])
log.Println(args[0][1:])
if cmd == args[0] || cmd[1:] == args[0] {
buffer.WriteString(plug.GetName())
buffer.WriteString("\n")
for _, help := range plug.GetHelpText() {
buffer.WriteString(" ")
buffer.WriteString(help)
buffer.WriteString("\n")
}
}
}
}
} else {
buffer.WriteString(config.Plugins["about_text"])
buffer.WriteString("\n\n")
for _, plug := range plugins {
val, _ := config.EnabledPlugins[plugin.GetName()]
buffer.WriteString(plug.GetName())
if !val {
buffer.WriteString(" (disabled)")
}
buffer.WriteString("\n")
for _, cmd := range plug.GetHelpText() {
buffer.WriteString(" ")
buffer.WriteString(cmd)
buffer.WriteString("\n")
}
buffer.WriteString("\n")
}
}
msg.Text = buffer.String()
bot.sendMessage(msg)
}

@ -1,153 +0,0 @@
package main
import (
"fmt"
"log"
"strings"
)
type ManagePlugin struct {
}
func (plugin *ManagePlugin) GetName() string {
return "Plugin manager"
}
func (plugin *ManagePlugin) GetCommands() []string {
return []string{
"/enable",
"Enable",
"/disable",
"Disable",
"/reload",
}
}
func (plugin *ManagePlugin) GetHelpText() []string {
return []string{
"/enable [name] - enables a plugin",
"/disable [name] - disables a plugin",
"/reload - reloads bot configuration",
}
}
func (plugin *ManagePlugin) Setup() {
}
func (plugin *ManagePlugin) GotCommand(command string, message Message, args []string) {
log.Println(command)
if command == "/enable" {
keyboard := [][]string{}
hasDisabled := false
for _, plug := range plugins {
enabled, _ := config.EnabledPlugins[plug.GetName()]
if enabled {
continue
}
hasDisabled = true
keyboard = append(keyboard, []string{"Enable " + plug.GetName()})
}
if !hasDisabled {
msg := NewMessage(message.Chat.Id, "All plugins are enabled!")
msg.ReplyToMessageId = message.MessageId
bot.sendMessage(msg)
return
}
msg := NewMessage(message.Chat.Id, "Please specify which plugin to enable")
msg.ReplyToMessageId = message.MessageId
msg.ReplyMarkup = ReplyKeyboardMarkup{
Keyboard: keyboard,
OneTimeKeyboard: true,
Selective: true,
ResizeKeyboard: true,
}
bot.sendMessage(msg)
} else if command == "Enable" {
pluginName := strings.SplitN(message.Text, " ", 2)
msg := NewMessage(message.Chat.Id, "")
msg.ReplyToMessageId = message.MessageId
msg.ReplyMarkup = ReplyKeyboardHide{
HideKeyboard: true,
Selective: true,
}
_, ok := config.EnabledPlugins[pluginName[1]]
if !ok {
msg.Text = "Unknown plugin!"
msg.ReplyToMessageId = message.MessageId
bot.sendMessage(msg)
return
}
config.EnabledPlugins[pluginName[1]] = true
msg.Text = fmt.Sprintf("Enabled '%s'!", pluginName[1])
bot.sendMessage(msg)
} else if command == "/disable" {
keyboard := [][]string{}
hasEnabled := false
for _, plug := range plugins {
enabled, _ := config.EnabledPlugins[plug.GetName()]
if !enabled {
continue
}
hasEnabled = true
keyboard = append(keyboard, []string{"Disable " + plug.GetName()})
}
if !hasEnabled {
msg := NewMessage(message.Chat.Id, "All plugins are disabled!")
msg.ReplyToMessageId = message.MessageId
bot.sendMessage(msg)
return
}
msg := NewMessage(message.Chat.Id, "Please specify which plugin to disable")
msg.ReplyToMessageId = message.MessageId
msg.ReplyMarkup = ReplyKeyboardMarkup{
Keyboard: keyboard,
OneTimeKeyboard: true,
Selective: true,
ResizeKeyboard: true,
}
bot.sendMessage(msg)
} else if command == "Disable" {
pluginName := strings.SplitN(message.Text, " ", 2)
msg := NewMessage(message.Chat.Id, "")
msg.ReplyToMessageId = message.MessageId
msg.ReplyMarkup = ReplyKeyboardHide{
HideKeyboard: true,
Selective: true,
}
_, ok := config.EnabledPlugins[pluginName[1]]
if !ok {
msg.Text = "Unknown plugin!"
msg.ReplyToMessageId = message.MessageId
bot.sendMessage(msg)
return
}
config.EnabledPlugins[pluginName[1]] = false
msg.Text = fmt.Sprintf("Disabled '%s'!", pluginName[1])
bot.sendMessage(msg)
}
saveConfig()
}

@ -1,4 +1,4 @@
package main
package tgbotapi
import (
"encoding/json"

@ -0,0 +1,22 @@
package tgbotapi
func (bot *BotApi) UpdatesChan(config UpdateConfig) (chan Update, error) {
bot.Updates = make(chan Update, 100)
go func() {
updates, err := bot.GetUpdates(config)
if err != nil {
panic(err)
}
for _, update := range updates {
if update.UpdateId > config.Offset {
config.Offset = update.UpdateId + 1
}
bot.Updates <- update
}
}()
return bot.Updates, nil
}