merge upstream
Jqs7 7@jqs7.com
Tue, 18 Aug 2015 09:48:17 +0800
4 files changed,
108 insertions(+),
33 deletions(-)
M
methods.go
→
methods.go
@@ -1,18 +1,17 @@
package tgbotapi import ( - "bytes" "encoding/json" "errors" "fmt" - "io" "io/ioutil" "log" - "mime/multipart" "net/http" "net/url" "os" "strconv" + + "github.com/technoweenie/multipartstreamer" ) // Telegram constants@@ -193,46 +192,32 @@ // UploadFile makes a request to the API with a file.
// // 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) { - var b bytes.Buffer - w := multipart.NewWriter(&b) - f, err := os.Open(filename) if err != nil { return APIResponse{}, err } + defer f.Close() - fw, err := w.CreateFormFile(fieldname, filename) + fi, err := os.Stat(filename) if err != nil { return APIResponse{}, err } - if _, err = io.Copy(fw, f); err != nil { - return APIResponse{}, err - } + ms := multipartstreamer.New() + ms.WriteFields(params) + ms.WriteReader(fieldname, f.Name(), fi.Size(), f) - for key, val := range params { - if fw, err = w.CreateFormField(key); err != nil { - 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) + req, err := http.NewRequest("POST", fmt.Sprintf(APIEndpoint, bot.Token, endpoint), nil) + ms.SetupRequest(req) if err != nil { return APIResponse{}, err } - req.Header.Set("Content-Type", w.FormDataContentType()) - res, err := bot.Client.Do(req) if err != nil { return APIResponse{}, err } + defer res.Body.Close() bytes, err := ioutil.ReadAll(res.Body) if err != nil {@@ -408,6 +393,7 @@ //
// when the fields title and performer are both empty // 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. +// You may use the tgutils.EncodeAudio func to assist you with this, if needed. // // Requires ChatID and FileID OR FilePath. // ReplyToMessageID and ReplyMarkup are optional.@@ -561,6 +547,7 @@ }
// SendVoice sends or uploads a playable voice to a chat. // 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. // ReplyToMessageID and ReplyMarkup are optional.
A
tgutils/audio.go
@@ -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 +}
M
types.go
→
types.go
@@ -80,7 +80,7 @@ Location Location `json:"location"`
NewChatParticipant User `json:"new_chat_participant"` LeftChatParticipant User `json:"left_chat_participant"` NewChatTitle string `json:"new_chat_title"` - NewChatPhoto string `json:"new_chat_photo"` + NewChatPhoto []PhotoSize `json:"new_chat_photo"` DeleteChatPhoto bool `json:"delete_chat_photo"` GroupChatCreated bool `json:"group_chat_created"` }
M
updates.go
→
updates.go
@@ -13,13 +13,9 @@ go func() {
for { updates, err := bot.GetUpdates(config) if err != nil { - if bot.Debug { - panic(err) - } else { - log.Println(err) - log.Println("Failed to get updates, retrying in 3 seconds...") - time.Sleep(time.Second * 3) - } + log.Println(err) + log.Println("Failed to get updates, retrying in 3 seconds...") + time.Sleep(time.Second * 3) continue }