merge upstream

bot-api-6.1
Jqs7 2015-08-18 09:48:17 +08:00
commit ae7c1b4e22
4 changed files with 108 additions and 33 deletions

View File

@ -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.

92
tgutils/audio.go 100644
View File

@ -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
}

View File

@ -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"`
} }

View File

@ -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
} }