Finish basic file upload support. Fixes #62
This commit is contained in:
@ -819,6 +819,28 @@ func (c *Container) MarkRead(roomID id.RoomID, eventID id.EventID) {
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *Container) PrepareMediaMessage(room *rooms.Room, path string, rel *ifc.Relation) (*muksevt.Event, error) {
|
||||
resp, err := c.UploadMedia(path, room.Encrypted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content := event.MessageEventContent{
|
||||
MsgType: resp.MsgType,
|
||||
Body: resp.Name,
|
||||
Info: resp.Info,
|
||||
}
|
||||
if resp.EncryptionInfo != nil {
|
||||
content.File = &event.EncryptedFileInfo{
|
||||
EncryptedFile: *resp.EncryptionInfo,
|
||||
URL: resp.ContentURI.CUString(),
|
||||
}
|
||||
} else {
|
||||
content.URL = resp.ContentURI.CUString()
|
||||
}
|
||||
|
||||
return c.prepareEvent(room.ID, &content, rel), nil
|
||||
}
|
||||
|
||||
func (c *Container) PrepareMarkdownMessage(roomID id.RoomID, msgtype event.MessageType, text, html string, rel *ifc.Relation) *muksevt.Event {
|
||||
var content event.MessageEventContent
|
||||
if html != "" {
|
||||
@ -833,8 +855,12 @@ func (c *Container) PrepareMarkdownMessage(roomID id.RoomID, msgtype event.Messa
|
||||
content.MsgType = msgtype
|
||||
}
|
||||
|
||||
return c.prepareEvent(roomID, &content, rel)
|
||||
}
|
||||
|
||||
func (c *Container) prepareEvent(roomID id.RoomID, content *event.MessageEventContent, rel *ifc.Relation) *muksevt.Event {
|
||||
if rel != nil && rel.Type == event.RelReplace {
|
||||
contentCopy := content
|
||||
contentCopy := *content
|
||||
content.NewContent = &contentCopy
|
||||
content.Body = "* " + content.Body
|
||||
if len(content.FormattedBody) > 0 {
|
||||
@ -855,7 +881,7 @@ func (c *Container) PrepareMarkdownMessage(roomID id.RoomID, msgtype event.Messa
|
||||
Type: event.EventMessage,
|
||||
Timestamp: time.Now().UnixNano() / 1e6,
|
||||
RoomID: roomID,
|
||||
Content: event.Content{Parsed: &content},
|
||||
Content: event.Content{Parsed: content},
|
||||
Unsigned: event.Unsigned{TransactionID: txnID},
|
||||
})
|
||||
localEcho.Gomuks.OutgoingState = muksevt.StateLocalEcho
|
||||
@ -905,18 +931,60 @@ func (c *Container) SendEvent(evt *muksevt.Event) (id.EventID, error) {
|
||||
return resp.EventID, nil
|
||||
}
|
||||
|
||||
func (c *Container) SendImage(roomID id.RoomID, body string, url id.ContentURI) {
|
||||
func (c *Container) UploadMedia(path string, encrypt bool) (*ifc.UploadedMediaInfo, error) {
|
||||
var err error
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get absolute path")
|
||||
}
|
||||
|
||||
}
|
||||
msgtype, info, err := getMediaInfo(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *Container) UploadMedia(data mautrix.ReqUploadMedia) (*id.ContentURI, error) {
|
||||
resp, err := c.client.UploadMedia(data)
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open file")
|
||||
}
|
||||
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get file info")
|
||||
}
|
||||
|
||||
uploadFileName := stat.Name()
|
||||
uploadMimeType := info.MimeType
|
||||
|
||||
var content io.Reader
|
||||
var encryptionInfo *attachment.EncryptedFile
|
||||
if encrypt {
|
||||
uploadMimeType = "application/octet-stream"
|
||||
uploadFileName = ""
|
||||
encryptionInfo = attachment.NewEncryptedFile()
|
||||
content = encryptionInfo.EncryptStream(file)
|
||||
} else {
|
||||
content = file
|
||||
}
|
||||
|
||||
resp, err := c.client.UploadMedia(mautrix.ReqUploadMedia{
|
||||
Content: content,
|
||||
ContentLength: stat.Size(),
|
||||
ContentType: uploadMimeType,
|
||||
FileName: uploadFileName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &resp.ContentURI, nil
|
||||
return &ifc.UploadedMediaInfo{
|
||||
RespMediaUpload: resp,
|
||||
EncryptionInfo: encryptionInfo,
|
||||
Name: stat.Name(),
|
||||
MsgType: msgtype,
|
||||
Info: &info,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Container) sendTypingAsync(roomID id.RoomID, typing bool, timeout int64) {
|
||||
|
106
matrix/mediainfo.go
Normal file
106
matrix/mediainfo.go
Normal file
@ -0,0 +1,106 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2020 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"image"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/vansante/go-ffprobe.v2"
|
||||
|
||||
"maunium.net/go/gomuks/debug"
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
func getImageInfo(path string) (event.FileInfo, error) {
|
||||
var info event.FileInfo
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return info, errors.Wrap(err, "failed to open image to get info")
|
||||
}
|
||||
cfg, _, err := image.DecodeConfig(file)
|
||||
if err != nil {
|
||||
return info, errors.Wrap(err, "failed to get image info")
|
||||
}
|
||||
info.Width = cfg.Width
|
||||
info.Height = cfg.Height
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func getFFProbeInfo(mimeClass, path string) (msgtype event.MessageType, info event.FileInfo, err error) {
|
||||
ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancelFn()
|
||||
var probedInfo *ffprobe.ProbeData
|
||||
probedInfo, err = ffprobe.ProbeURL(ctx, path)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("failed to get %s info with ffprobe", mimeClass))
|
||||
return
|
||||
}
|
||||
if mimeClass == "audio" {
|
||||
msgtype = event.MsgAudio
|
||||
stream := probedInfo.FirstAudioStream()
|
||||
if stream != nil {
|
||||
info.Duration = int(stream.DurationTs)
|
||||
}
|
||||
} else {
|
||||
msgtype = event.MsgVideo
|
||||
stream := probedInfo.FirstVideoStream()
|
||||
if stream != nil {
|
||||
info.Duration = int(stream.DurationTs)
|
||||
info.Width = stream.Width
|
||||
info.Height = stream.Height
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getMediaInfo(path string) (msgtype event.MessageType, info event.FileInfo, err error) {
|
||||
var mime *mimetype.MIME
|
||||
mime, err = mimetype.DetectFile(path)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "failed to get content type")
|
||||
return
|
||||
}
|
||||
|
||||
mimeClass := strings.SplitN(mime.String(), "/", 2)[0]
|
||||
switch mimeClass {
|
||||
case "image":
|
||||
msgtype = event.MsgImage
|
||||
info, err = getImageInfo(path)
|
||||
if err != nil {
|
||||
debug.Printf("Failed to get image info for %s: %v", err)
|
||||
err = nil
|
||||
}
|
||||
case "audio", "video":
|
||||
msgtype, info, err = getFFProbeInfo(mimeClass, path)
|
||||
if err != nil {
|
||||
debug.Printf("Failed to get ffprobe info for %s: %v", err)
|
||||
err = nil
|
||||
}
|
||||
default:
|
||||
msgtype = event.MsgFile
|
||||
}
|
||||
info.MimeType = mime.String()
|
||||
|
||||
return
|
||||
}
|
Reference in New Issue
Block a user