Move lottie_convert.py conversion code to its own file
This commit is contained in:
@@ -5,10 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -239,66 +236,3 @@ func ConvertWebPToPNG(data *[]byte) error {
|
|||||||
*data = w.Bytes()
|
*data = w.Bytes()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
|
|
||||||
func CanConvertTgsToX() error {
|
|
||||||
// We depend on the fact that `lottie_convert.py --help` has exit status 0.
|
|
||||||
// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
|
|
||||||
// However, there is no alternative like `lottie_convert.py --is-properly-installed`
|
|
||||||
cmd := exec.Command("lottie_convert.py", "--help")
|
|
||||||
return cmd.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
|
|
||||||
// This relies on an external command, which is ugly, but works.
|
|
||||||
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
|
|
||||||
// lottie can't handle input from a pipe, so write to a temporary file:
|
|
||||||
tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
tmpInFileName := tmpInFile.Name()
|
|
||||||
defer func() {
|
|
||||||
if removeErr := os.Remove(tmpInFileName); removeErr != nil {
|
|
||||||
logger.Errorf("Could not delete temporary (input) file %s: %v", tmpInFileName, removeErr)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
// lottie can handle writing to a pipe, but there is no way to do that platform-independently.
|
|
||||||
// "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file:
|
|
||||||
tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
tmpOutFileName := tmpOutFile.Name()
|
|
||||||
defer func() {
|
|
||||||
if removeErr := os.Remove(tmpOutFileName); removeErr != nil {
|
|
||||||
logger.Errorf("Could not delete temporary (output) file %s: %v", tmpOutFileName, removeErr)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, writeErr := tmpInFile.Write(*data); writeErr != nil {
|
|
||||||
return writeErr
|
|
||||||
}
|
|
||||||
// Must close before calling lottie to avoid data races:
|
|
||||||
if closeErr := tmpInFile.Close(); closeErr != nil {
|
|
||||||
return closeErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call lottie to transform:
|
|
||||||
cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpInFileName, tmpOutFileName)
|
|
||||||
cmd.Stdout = nil
|
|
||||||
cmd.Stderr = nil
|
|
||||||
// NB: lottie writes progress into to stderr in all cases.
|
|
||||||
_, stderr := cmd.Output()
|
|
||||||
if stderr != nil {
|
|
||||||
// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
|
|
||||||
return stderr
|
|
||||||
}
|
|
||||||
dataContents, err := ioutil.ReadFile(tmpOutFileName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = dataContents
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
89
bridge/helper/lottie_convert.go
Normal file
89
bridge/helper/lottie_convert.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// +build !cgo
|
||||||
|
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CanConvertTgsToX Checks whether the external command necessary for ConvertTgsToX works.
|
||||||
|
func CanConvertTgsToX() error {
|
||||||
|
// We depend on the fact that `lottie_convert.py --help` has exit status 0.
|
||||||
|
// Hyrum's Law predicted this, and Murphy's Law predicts that this will break eventually.
|
||||||
|
// However, there is no alternative like `lottie_convert.py --is-properly-installed`
|
||||||
|
cmd := exec.Command("lottie_convert.py", "--help")
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertTgsToWebP convert input data (which should be tgs format) to WebP format
|
||||||
|
// This relies on an external command, which is ugly, but works.
|
||||||
|
func ConvertTgsToX(data *[]byte, outputFormat string, logger *logrus.Entry) error {
|
||||||
|
// lottie can't handle input from a pipe, so write to a temporary file:
|
||||||
|
tmpInFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-input-*.tgs")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tmpInFileName := tmpInFile.Name()
|
||||||
|
defer func() {
|
||||||
|
if removeErr := os.Remove(tmpInFileName); removeErr != nil {
|
||||||
|
logger.Errorf("Could not delete temporary (input) file %s: %v", tmpInFileName, removeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// lottie can handle writing to a pipe, but there is no way to do that platform-independently.
|
||||||
|
// "/dev/stdout" won't work on Windows, and "-" upsets Cairo for some reason. So we need another file:
|
||||||
|
tmpOutFile, err := ioutil.TempFile(os.TempDir(), "matterbridge-lottie-output-*.data")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tmpOutFileName := tmpOutFile.Name()
|
||||||
|
defer func() {
|
||||||
|
if removeErr := os.Remove(tmpOutFileName); removeErr != nil {
|
||||||
|
logger.Errorf("Could not delete temporary (output) file %s: %v", tmpOutFileName, removeErr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, writeErr := tmpInFile.Write(*data); writeErr != nil {
|
||||||
|
return writeErr
|
||||||
|
}
|
||||||
|
// Must close before calling lottie to avoid data races:
|
||||||
|
if closeErr := tmpInFile.Close(); closeErr != nil {
|
||||||
|
return closeErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call lottie to transform:
|
||||||
|
cmd := exec.Command("lottie_convert.py", "--input-format", "lottie", "--output-format", outputFormat, tmpInFileName, tmpOutFileName)
|
||||||
|
cmd.Stdout = nil
|
||||||
|
cmd.Stderr = nil
|
||||||
|
// NB: lottie writes progress into to stderr in all cases.
|
||||||
|
_, stderr := cmd.Output()
|
||||||
|
if stderr != nil {
|
||||||
|
// 'stderr' already contains some parts of Stderr, because it was set to 'nil'.
|
||||||
|
return stderr
|
||||||
|
}
|
||||||
|
dataContents, err := ioutil.ReadFile(tmpOutFileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*data = dataContents
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SupportsFormat(format string) bool {
|
||||||
|
switch format {
|
||||||
|
case "png":
|
||||||
|
fallthrough
|
||||||
|
case "webp":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func LottieBackend() string {
|
||||||
|
return "lottie_convert.py"
|
||||||
|
}
|
||||||
@@ -220,20 +220,10 @@ func (b *Btelegram) handleDownloadAvatar(userid int, channel string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
|
func (b *Btelegram) maybeConvertTgs(name *string, data *[]byte) {
|
||||||
var format string
|
format := b.GetString("MediaConvertTgs")
|
||||||
switch b.GetString("MediaConvertTgs") {
|
if helper.SupportsFormat(format) {
|
||||||
case FormatWebp:
|
b.Log.Debugf("Format supported by %s, converting %v", helper.LottieBackend(), name)
|
||||||
b.Log.Debugf("Tgs to WebP conversion enabled, converting %v", name)
|
} else {
|
||||||
format = FormatWebp
|
|
||||||
case FormatPng:
|
|
||||||
// The WebP to PNG converter can't handle animated webp files yet,
|
|
||||||
// and I'm not going to write a path for x/image/webp.
|
|
||||||
// The error message would be:
|
|
||||||
// conversion failed: webp: non-Alpha VP8X is not implemented
|
|
||||||
// So instead, we tell lottie to directly go to PNG.
|
|
||||||
b.Log.Debugf("Tgs to PNG conversion enabled, converting %v", name)
|
|
||||||
format = FormatPng
|
|
||||||
default:
|
|
||||||
// Otherwise, no conversion was requested. Trying to run the usual webp
|
// Otherwise, no conversion was requested. Trying to run the usual webp
|
||||||
// converter would fail, because '.tgs.webp' is actually a gzipped JSON
|
// converter would fail, because '.tgs.webp' is actually a gzipped JSON
|
||||||
// file, and has nothing to do with WebP.
|
// file, and has nothing to do with WebP.
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ const (
|
|||||||
HTMLFormat = "HTML"
|
HTMLFormat = "HTML"
|
||||||
HTMLNick = "htmlnick"
|
HTMLNick = "htmlnick"
|
||||||
MarkdownV2 = "MarkdownV2"
|
MarkdownV2 = "MarkdownV2"
|
||||||
FormatPng = "png"
|
|
||||||
FormatWebp = "webp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Btelegram struct {
|
type Btelegram struct {
|
||||||
@@ -32,10 +30,10 @@ func New(cfg *bridge.Config) bridge.Bridger {
|
|||||||
if tgsConvertFormat != "" {
|
if tgsConvertFormat != "" {
|
||||||
err := helper.CanConvertTgsToX()
|
err := helper.CanConvertTgsToX()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but lottie does not appear to work:\n%#v", tgsConvertFormat, err)
|
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s does not appear to work:\n%#v", tgsConvertFormat, helper.LottieBackend(), err)
|
||||||
}
|
}
|
||||||
if tgsConvertFormat != FormatPng && tgsConvertFormat != FormatWebp {
|
if !helper.SupportsFormat(tgsConvertFormat) {
|
||||||
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but only '%s' and '%s' are supported.", FormatPng, FormatWebp, tgsConvertFormat)
|
log.Fatalf("Telegram bridge configured to convert .tgs files to '%s', but %s doesn't support it.", tgsConvertFormat, helper.LottieBackend())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Btelegram{Config: cfg, avatarMap: make(map[string]string)}
|
return &Btelegram{Config: cfg, avatarMap: make(map[string]string)}
|
||||||
|
|||||||
Reference in New Issue
Block a user