merge upstream
commit
ae7c1b4e22
37
methods.go
37
methods.go
|
@ -1,18 +1,17 @@
|
||||||
package tgbotapi
|
package tgbotapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"mime/multipart"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/technoweenie/multipartstreamer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Telegram constants
|
// Telegram constants
|
||||||
|
@ -193,46 +192,32 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
|
||||||
//
|
//
|
||||||
// Requires the parameter to hold the file not be in the params.
|
// Requires the parameter to hold the file not be in the params.
|
||||||
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)
|
|
||||||
|
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
fw, err := w.CreateFormFile(fieldname, filename)
|
fi, err := os.Stat(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = io.Copy(fw, f); err != nil {
|
ms := multipartstreamer.New()
|
||||||
return APIResponse{}, err
|
ms.WriteFields(params)
|
||||||
}
|
ms.WriteReader(fieldname, f.Name(), fi.Size(), f)
|
||||||
|
|
||||||
for key, val := range params {
|
req, err := http.NewRequest("POST", fmt.Sprintf(APIEndpoint, bot.Token, endpoint), nil)
|
||||||
if fw, err = w.CreateFormField(key); err != nil {
|
ms.SetupRequest(req)
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = fw.Write([]byte(val)); err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", fmt.Sprintf(APIEndpoint, bot.Token, endpoint), &b)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
|
||||||
|
|
||||||
res, err := bot.Client.Do(req)
|
res, err := bot.Client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return APIResponse{}, err
|
||||||
}
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
bytes, err := ioutil.ReadAll(res.Body)
|
bytes, err := ioutil.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -408,6 +393,7 @@ func (bot *BotAPI) SendPhoto(config PhotoConfig) (Message, error) {
|
||||||
// when the fields title and performer are both empty
|
// when the fields title and performer are both empty
|
||||||
// and the mime-type of the file to be sent is not audio/mpeg,
|
// and the mime-type of the file to be sent is not audio/mpeg,
|
||||||
// the file must be in an .ogg file encoded with OPUS.
|
// the file must be in an .ogg file encoded with OPUS.
|
||||||
|
// You may use the tgutils.EncodeAudio func to assist you with this, if needed.
|
||||||
//
|
//
|
||||||
// Requires ChatID and FileID OR FilePath.
|
// Requires ChatID and FileID OR FilePath.
|
||||||
// ReplyToMessageID and ReplyMarkup are optional.
|
// ReplyToMessageID and ReplyMarkup are optional.
|
||||||
|
@ -561,6 +547,7 @@ func (bot *BotAPI) SendDocument(config DocumentConfig) (Message, error) {
|
||||||
|
|
||||||
// SendVoice sends or uploads a playable voice to a chat.
|
// SendVoice sends or uploads a playable voice to a chat.
|
||||||
// If using a file, the file must be encoded as an .ogg with OPUS.
|
// If using a file, the file must be encoded as an .ogg with OPUS.
|
||||||
|
// You may use the tgutils.EncodeAudio func to assist you with this, if needed.
|
||||||
//
|
//
|
||||||
// Requires ChatID and FileID OR FilePath.
|
// Requires ChatID and FileID OR FilePath.
|
||||||
// ReplyToMessageID and ReplyMarkup are optional.
|
// ReplyToMessageID and ReplyMarkup are optional.
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Package tgutils provides extra functions to make certain tasks easier.
|
||||||
|
package tgutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/syfaro/telegram-bot-api"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rand uint32
|
||||||
|
var randmu sync.Mutex
|
||||||
|
|
||||||
|
func reseed() uint32 {
|
||||||
|
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextSuffix() string {
|
||||||
|
randmu.Lock()
|
||||||
|
r := rand
|
||||||
|
if r == 0 {
|
||||||
|
r = reseed()
|
||||||
|
}
|
||||||
|
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
||||||
|
rand = r
|
||||||
|
randmu.Unlock()
|
||||||
|
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function ripped from ioutils.TempFile, except with a suffix, instead of prefix.
|
||||||
|
func tempFileWithSuffix(dir, suffix string) (f *os.File, err error) {
|
||||||
|
if dir == "" {
|
||||||
|
dir = os.TempDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
nconflict := 0
|
||||||
|
for i := 0; i < 10000; i++ {
|
||||||
|
name := filepath.Join(dir, nextSuffix()+suffix)
|
||||||
|
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
||||||
|
if os.IsExist(err) {
|
||||||
|
if nconflict++; nconflict > 10 {
|
||||||
|
randmu.Lock()
|
||||||
|
rand = reseed()
|
||||||
|
randmu.Unlock()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeAudio takes a file and attempts to convert it to a .ogg for Telegram.
|
||||||
|
// It then updates the path to the audio file in the AudioConfig.
|
||||||
|
//
|
||||||
|
// This function requires ffmpeg and opusenc to be installed on the system!
|
||||||
|
func EncodeAudio(audio *tgbotapi.AudioConfig) error {
|
||||||
|
f, err := tempFileWithSuffix(os.TempDir(), "_tgutils.ogg")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
ffmpegArgs := []string{
|
||||||
|
"-i",
|
||||||
|
audio.FilePath,
|
||||||
|
"-f",
|
||||||
|
"wav",
|
||||||
|
"-",
|
||||||
|
}
|
||||||
|
|
||||||
|
opusArgs := []string{
|
||||||
|
"--bitrate",
|
||||||
|
"256",
|
||||||
|
"-",
|
||||||
|
f.Name(),
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 := exec.Command("ffmpeg", ffmpegArgs...)
|
||||||
|
c2 := exec.Command("opusenc", opusArgs...)
|
||||||
|
|
||||||
|
c2.Stdin, _ = c1.StdoutPipe()
|
||||||
|
c2.Stdout = os.Stdout
|
||||||
|
c2.Start()
|
||||||
|
c1.Run()
|
||||||
|
c2.Wait()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
2
types.go
2
types.go
|
@ -80,7 +80,7 @@ type Message struct {
|
||||||
NewChatParticipant User `json:"new_chat_participant"`
|
NewChatParticipant User `json:"new_chat_participant"`
|
||||||
LeftChatParticipant User `json:"left_chat_participant"`
|
LeftChatParticipant User `json:"left_chat_participant"`
|
||||||
NewChatTitle string `json:"new_chat_title"`
|
NewChatTitle string `json:"new_chat_title"`
|
||||||
NewChatPhoto string `json:"new_chat_photo"`
|
NewChatPhoto []PhotoSize `json:"new_chat_photo"`
|
||||||
DeleteChatPhoto bool `json:"delete_chat_photo"`
|
DeleteChatPhoto bool `json:"delete_chat_photo"`
|
||||||
GroupChatCreated bool `json:"group_chat_created"`
|
GroupChatCreated bool `json:"group_chat_created"`
|
||||||
}
|
}
|
||||||
|
|
10
updates.go
10
updates.go
|
@ -13,13 +13,9 @@ func (bot *BotAPI) UpdatesChan(config UpdateConfig) error {
|
||||||
for {
|
for {
|
||||||
updates, err := bot.GetUpdates(config)
|
updates, err := bot.GetUpdates(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if bot.Debug {
|
log.Println(err)
|
||||||
panic(err)
|
log.Println("Failed to get updates, retrying in 3 seconds...")
|
||||||
} else {
|
time.Sleep(time.Second * 3)
|
||||||
log.Println(err)
|
|
||||||
log.Println("Failed to get updates, retrying in 3 seconds...")
|
|
||||||
time.Sleep(time.Second * 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue