123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- package main
- import (
- "bytes"
- "fmt"
- "image"
- "io"
- "net/http"
- "strings"
- "time"
- "github.com/bwmarrin/discordgo"
- "github.com/gabriel-vasile/mimetype"
- "maunium.net/go/mautrix"
- "maunium.net/go/mautrix/appservice"
- "maunium.net/go/mautrix/crypto/attachment"
- "maunium.net/go/mautrix/event"
- "go.mau.fi/mautrix-discord/database"
- )
- func downloadDiscordAttachment(url string) ([]byte, error) {
- req, err := http.NewRequest(http.MethodGet, url, nil)
- if err != nil {
- return nil, err
- }
- for key, value := range discordgo.DroidDownloadHeaders {
- req.Header.Set(key, value)
- }
- resp, err := http.DefaultClient.Do(req)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- if resp.StatusCode > 300 {
- data, _ := io.ReadAll(resp.Body)
- return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, data)
- }
- return io.ReadAll(resp.Body)
- }
- func uploadDiscordAttachment(url string, data []byte) error {
- req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader(data))
- if err != nil {
- return err
- }
- for key, value := range discordgo.DroidFetchHeaders {
- req.Header.Set(key, value)
- }
- resp, err := http.DefaultClient.Do(req)
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- if resp.StatusCode > 300 {
- respData, _ := io.ReadAll(resp.Body)
- return fmt.Errorf("unexpected status %d: %s", resp.StatusCode, respData)
- }
- return nil
- }
- func (portal *Portal) downloadMatrixAttachment(content *event.MessageEventContent) ([]byte, error) {
- var file *event.EncryptedFileInfo
- rawMXC := content.URL
- if content.File != nil {
- file = content.File
- rawMXC = file.URL
- }
- mxc, err := rawMXC.Parse()
- if err != nil {
- return nil, err
- }
- data, err := portal.MainIntent().DownloadBytes(mxc)
- if err != nil {
- return nil, err
- }
- if file != nil {
- err = file.DecryptInPlace(data)
- if err != nil {
- return nil, err
- }
- }
- return data, nil
- }
- func (br *DiscordBridge) uploadMatrixAttachment(intent *appservice.IntentAPI, data []byte, url string, encrypt bool, attachmentID, mime string) (*database.File, error) {
- dbFile := br.DB.File.New()
- dbFile.Timestamp = time.Now()
- dbFile.URL = url
- dbFile.ID = attachmentID
- dbFile.Size = len(data)
- dbFile.MimeType = mimetype.Detect(data).String()
- if mime == "" {
- mime = dbFile.MimeType
- }
- if strings.HasPrefix(mime, "image/") {
- cfg, _, _ := image.DecodeConfig(bytes.NewReader(data))
- dbFile.Width = cfg.Width
- dbFile.Height = cfg.Height
- }
- uploadMime := mime
- if encrypt {
- dbFile.Encrypted = true
- dbFile.DecryptionInfo = attachment.NewEncryptedFile()
- dbFile.DecryptionInfo.EncryptInPlace(data)
- uploadMime = "application/octet-stream"
- }
- req := mautrix.ReqUploadMedia{
- ContentBytes: data,
- ContentType: uploadMime,
- }
- if br.Config.Homeserver.AsyncMedia {
- resp, err := intent.UnstableCreateMXC()
- if err != nil {
- return nil, err
- }
- dbFile.MXC = resp.ContentURI
- req.UnstableMXC = resp.ContentURI
- req.UploadURL = resp.UploadURL
- go func() {
- _, err = intent.UploadMedia(req)
- if err != nil {
- br.Log.Errorfln("Failed to upload %s: %v", req.UnstableMXC, err)
- dbFile.Delete()
- }
- }()
- } else {
- uploaded, err := intent.UploadMedia(req)
- if err != nil {
- return nil, err
- }
- dbFile.MXC = uploaded.ContentURI
- }
- dbFile.Insert(nil)
- return dbFile, nil
- }
- func (br *DiscordBridge) copyAttachmentToMatrix(intent *appservice.IntentAPI, url string, encrypt bool, attachmentID, mime string) (*database.File, error) {
- dbFile := br.DB.File.Get(url, encrypt)
- if dbFile == nil {
- data, err := downloadDiscordAttachment(url)
- if err != nil {
- return nil, err
- }
- dbFile, err = br.uploadMatrixAttachment(intent, data, url, encrypt, attachmentID, mime)
- if err != nil {
- return nil, err
- }
- }
- return dbFile, nil
- }
|