func createMediaMessage(message *tgbotapi.Message, destination int64, markup *tgbotapi.InlineKeyboardMarkup) (tgbotapi.Chattable, bool, error) {
	if message == nil {
		return nil, false, fmt.Errorf("cannot process empty message")
	}
	var chattable tgbotapi.Chattable
	switch {
	case message.Sticker != nil:
		sticker := tgbotapi.NewStickerShare(destination, message.Sticker.FileID)
		if markup != nil {
			sticker.ReplyMarkup = markup
		}
		chattable = sticker
	case message.Audio != nil:
		audio := tgbotapi.NewAudioShare(destination, message.Audio.FileID)
		if markup != nil {
			audio.ReplyMarkup = markup
		}
		chattable = audio
	case message.Document != nil:
		document := tgbotapi.NewDocumentShare(destination, message.Document.FileID)
		document.Caption = message.Caption
		if markup != nil {
			document.ReplyMarkup = markup
		}
		chattable = document
	case message.Photo != nil:
		photoID, err := largestPhotoFromMessage(message)
		if err != nil {
			return nil, false, err
		}
		photo := tgbotapi.NewPhotoShare(destination, photoID)
		photo.Caption = message.Caption
		if markup != nil {
			photo.ReplyMarkup = markup
		}
		chattable = photo
	case message.Video != nil:
		video := tgbotapi.NewVideoShare(destination, message.Video.FileID)
		video.Caption = message.Caption
		if markup != nil {
			video.ReplyMarkup = markup
		}
		chattable = video
	case message.Venue != nil:
		venue := tgbotapi.NewVenue(destination, message.Venue.Title, message.Venue.Address, message.Venue.Location.Latitude, message.Venue.Location.Longitude)
		if markup != nil {
			venue.ReplyMarkup = markup
		}
		chattable = venue
	case message.Location != nil:
		location := tgbotapi.NewLocation(destination, message.Location.Latitude, message.Location.Longitude)
		if markup != nil {
			location.ReplyMarkup = markup
		}
		chattable = location
	case message.Contact != nil:
		contact := tgbotapi.NewContact(destination, message.Contact.PhoneNumber, message.Contact.FirstName)
		if markup != nil {
			contact.ReplyMarkup = markup
		}
		chattable = contact
	default:
		return nil, false, nil
	}
	return chattable, true, nil
}
nolint: gocyclo
createMediaMessage returns a "Chattable" (which can be sent with bot.Send)
targeted at `destination', made with the media received in the message passed
as parameter, if there is any media in this message.
package main
import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)
func safeWriteJSON(data interface{}, file string) error {
	buf, err := json.Marshal(data)
	if err != nil {
		return err
	}
	datadir, err := dataDir()
	if err != nil {
		return err
	}
	tmpfile, err := ioutil.TempFile(datadir, "safe-write")
	if err != nil {
		log.Printf("safeWriteJSON: error creating temp file to save data: %v", err)
		return err
	}
	defer os.Remove(tmpfile.Name())
	if _, err = tmpfile.Write(buf); err != nil {
		log.Printf("safeWriteJSON: error writing data to temp file: %v", err)
		return err
	}
	if err = tmpfile.Close(); err != nil {
		log.Printf("safeWriteJSON: error closing temp file with data: %v", err)
		return err
	}
	f := filepath.Join(datadir, file)
	return os.Rename(tmpfile.Name(), f)
}
func readFromJSON(data interface{}, file string) error {
	buf, err := ioutil.ReadFile(file)
	if err != nil {
		return err
	}
	return json.Unmarshal(buf, data)
}
func readJSONFromDataDir(data interface{}, file string) error {
	datadir, err := dataDir()
	if err != nil {
		return err
	}
	f := filepath.Join(datadir, file)
	return readFromJSON(data, f)
}
func formatName(user tgbotapi.User) string {
	firstName := markdownEscape(user.FirstName)
	lastName := markdownEscape(user.LastName)
	return strings.Trim(fmt.Sprintf("%s %s", firstName, lastName), " ")
}
func markdownEscape(s string) string {
	s = strings.ReplaceAll(s, "*", "\\*")
	s = strings.ReplaceAll(s, "_", "\\_")
	s = strings.ReplaceAll(s, "[", "\\[")
	s = strings.ReplaceAll(s, "]", "\\]")
	s = strings.ReplaceAll(s, "`", "\\`")
	return s
}
func nameRef(user tgbotapi.User) string {
	username := user.UserName
	if username == "" || username != markdownEscape(username) {
		return formatName(user)
	}
	return "@" + username
}
func button(msg, label string) tgbotapi.InlineKeyboardButton {
	return tgbotapi.NewInlineKeyboardButtonData(msg, label)
}
func buttonURL(msg, url string) tgbotapi.InlineKeyboardButton {
	return tgbotapi.NewInlineKeyboardButtonURL(msg, url)
}
func sendPhotoReply(bot sender, chatid int64, messageid int, file interface{}, caption string) (tgbotapi.Message, error) {
	photoConfig := tgbotapi.NewPhotoUpload(chatid, file)
	photoConfig.Caption = caption
	photoConfig.ParseMode = parseModeMarkdown
	photoConfig.ReplyToMessageID = messageid
	return bot.Send(photoConfig)
}
func sendReply(bot sender, chatid int64, messageid int, text string) (tgbotapi.Message, error) {
	msg := tgbotapi.NewMessage(chatid, text)
	msg.ReplyToMessageID = messageid
	msg.ParseMode = parseModeMarkdown
	return bot.Send(msg)
}
func sendMessage(bot sender, chatid int64, text string) (tgbotapi.Message, error) {
	msg := tgbotapi.NewMessage(chatid, text)
	msg.ParseMode = parseModeMarkdown
	return bot.Send(msg)
}
func deleteMessage(bot deleteMessager, chatid int64, msgid int) {
	_, err := bot.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid})
	if err != nil {
		log.Printf("Unable to delete message (chat_id=%d, message_id=%d). Something is wrong.", chatid, msgid)
	}
	log.Printf("Removed message_id %d from chat_id %d", chatid, msgid)
}
func sendReplyWithMarkup(bot sender, chatID int64, msgID int, text string, markup tgbotapi.InlineKeyboardMarkup) (tgbotapi.Message, error) {
	msg := tgbotapi.NewMessage(chatID, text)
	msg.ReplyToMessageID = msgID
	msg.ReplyMarkup = &markup
	return bot.Send(msg)
}
func sendMessageWithMarkup(bot sender, chatID int64, msgID int, text string, markup tgbotapi.InlineKeyboardMarkup) (tgbotapi.Message, error) {
	msg := tgbotapi.NewMessage(chatID, text)
	msg.ReplyMarkup = &markup
	return bot.Send(msg)
}
func isPrivateChat(chat *tgbotapi.Chat) bool {
	return chat.Type == "private"
}
func isForwarded(msg *tgbotapi.Message) bool {
	if msg == nil {
		return false
	}
	return msg.ForwardFrom != nil || msg.ForwardFromChat != nil
}
func trDelete(s, substr string) string {
	ret := bytes.Buffer{}
	for _, r := range s {
		if strings.ContainsRune(substr, r) {
			continue
		}
		ret.WriteRune(r)
	}
	return ret.String()
}
func largestPhotoFromMessage(message *tgbotapi.Message) (string, error) {
	if message == nil {
		return "", fmt.Errorf("cannot process empty message")
	}
	if message.Photo == nil {
		return "", fmt.Errorf("message does not contain a photo")
	}
	largestPhotoDimension := 0
	indexLargestPhoto := 0
	dimension := 0
	for index, photoSize := range *message.Photo {
		dimension = photoSize.Width * photoSize.Height
		if dimension > largestPhotoDimension {
			largestPhotoDimension = dimension
			indexLargestPhoto = index
		}
	}
	return (*message.Photo)[indexLargestPhoto].FileID, nil
}