Move downloaded files to a permanent location

This commit is contained in:
Bohdan Horbeshko 2022-03-09 14:15:56 -05:00
parent 4307f85a04
commit 699d75552a
6 changed files with 70 additions and 196 deletions

View file

@ -4,6 +4,7 @@
:path: '/var/www/telegabber/content' # webserver workdir :path: '/var/www/telegabber/content' # webserver workdir
:link: 'http://tlgrm.localhost/content' # webserver public address :link: 'http://tlgrm.localhost/content' # webserver public address
:upload: 'https:///xmppfiles.localhost' # xmpp http upload address :upload: 'https:///xmppfiles.localhost' # xmpp http upload address
:user: 'www-data' # owner of content files
:tdlib_verbosity: 1 :tdlib_verbosity: 1
:tdlib: :tdlib:
:datadir: './sessions/' :datadir: './sessions/'

View file

@ -38,6 +38,7 @@ type TelegramContentConfig struct {
Path string `yaml:":path"` Path string `yaml:":path"`
Link string `yaml:":link"` Link string `yaml:":link"`
Upload string `yaml:":upload"` Upload string `yaml:":upload"`
User string `yaml:":user"`
} }
// TelegramTdlibConfig is for :tdlib: subtree // TelegramTdlibConfig is for :tdlib: subtree

View file

@ -21,6 +21,9 @@
}, },
":upload": { ":upload": {
"type": "string" "type": "string"
},
":user": {
"type": "string"
} }
} }
}, },

View file

@ -2,8 +2,6 @@ package telegram
import ( import (
"fmt" "fmt"
"os"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -107,13 +105,6 @@ func (c *Client) updateHandler() {
uhOh() uhOh()
} }
c.updateDeleteMessages(typedUpdate) c.updateDeleteMessages(typedUpdate)
case client.TypeUpdateFile:
typedUpdate, ok := update.(*client.UpdateFile)
if !ok {
uhOh()
}
c.updateFile(typedUpdate)
log.Debugf("%#v", typedUpdate.File)
case client.TypeUpdateAuthorizationState: case client.TypeUpdateAuthorizationState:
typedUpdate, ok := update.(*client.UpdateAuthorizationState) typedUpdate, ok := update.(*client.UpdateAuthorizationState)
if !ok { if !ok {
@ -214,10 +205,10 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
} }
} else { } else {
text = c.messageToText(update.Message, false) text = c.messageToText(update.Message, false)
file, filename := c.contentToFilename(content) file := c.contentToFile(content)
// download file(s) // download file (if one)
if file != nil && !file.Local.IsDownloadingCompleted { if file != nil {
newFile, err := c.DownloadFile(file.Id, 1, true) newFile, err := c.DownloadFile(file.Id, 1, true)
if err == nil { if err == nil {
file = newFile file = newFile
@ -226,7 +217,7 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
// OTR support (I do not know why would you need it, seriously) // OTR support (I do not know why would you need it, seriously)
if !(strings.HasPrefix(text, "?OTR") || c.Session.RawMessages) { if !(strings.HasPrefix(text, "?OTR") || c.Session.RawMessages) {
var prefix strings.Builder var prefix strings.Builder
prefix.WriteString(c.messageToPrefix(update.Message, c.formatContent(file, filename))) prefix.WriteString(c.messageToPrefix(update.Message, c.formatFile(file)))
if text != "" { if text != "" {
// \n if it is groupchat and message is not empty // \n if it is groupchat and message is not empty
if chatId < 0 { if chatId < 0 {
@ -275,27 +266,6 @@ func (c *Client) updateDeleteMessages(update *client.UpdateDeleteMessages) {
} }
} }
// file downloaded
func (c *Client) updateFile(update *client.UpdateFile) {
// not really
if !update.File.Local.IsDownloadingCompleted {
return
}
err := os.Symlink(
update.File.Local.Path,
c.formatFilePath(c.content.Path, update.File.Remote.UniqueId, filepath.Ext(update.File.Local.Path)),
)
if err != nil {
linkErr := err.(*os.LinkError)
if linkErr.Err.Error() == "file exists" {
log.Warn(err.Error())
} else {
log.Errorf("Error creating symlink: %v", err)
}
}
}
func (c *Client) updateAuthorizationState(update *client.UpdateAuthorizationState) { func (c *Client) updateAuthorizationState(update *client.UpdateAuthorizationState) {
switch update.AuthorizationState.AuthorizationStateType() { switch update.AuthorizationState.AuthorizationStateType() {
case client.TypeAuthorizationStateClosing: case client.TypeAuthorizationStateClosing:

View file

@ -2,11 +2,11 @@ package telegram
import ( import (
"crypto/sha1" "crypto/sha1"
"crypto/sha256"
"fmt" "fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"io" "io"
"os" "os"
osUser "os/user"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
@ -355,21 +355,56 @@ func (c *Client) formatForward(fwd *client.MessageForwardInfo) string {
return "Unknown forward type" return "Unknown forward type"
} }
func (c *Client) formatContent(file *client.File, filename string) string { func (c *Client) formatFile(file *client.File) string {
if file == nil { if file == nil || file.Local == nil || file.Remote == nil {
return "" return ""
} }
return fmt.Sprintf( var link string
"%s (%v kbytes) | %s", var src string
filename,
file.Size/1024,
c.formatFilePath(c.content.Link, file.Remote.UniqueId, filepath.Ext(file.Local.Path)),
)
}
func (c *Client) formatFilePath(basedir string, id string, ext string) string { if c.content.Path != "" && c.content.Link != "" {
return fmt.Sprintf("%s/%x%s", basedir, sha256.Sum256([]byte(id)), ext) src = file.Local.Path // source path
_, err := os.Stat(src)
if err != nil {
return ""
}
basename := file.Remote.UniqueId + filepath.Ext(src)
dest := c.content.Path + "/" + basename // destination path
link = c.content.Link + "/" + basename // download link
// move
err = os.Rename(src, dest)
if err != nil {
linkErr := err.(*os.LinkError)
if linkErr.Err.Error() == "file exists" {
log.Warn(err.Error())
} else {
log.Errorf("File moving error: %v", err)
return "<ERROR>"
}
}
// chown
if c.content.User != "" {
user, err := osUser.Lookup(c.content.User)
if err == nil {
uid, err := strconv.ParseInt(user.Uid, 10, 0)
if err == nil {
err = os.Chown(dest, int(uid), -1)
if err != nil {
log.Errorf("Chown error: %v", err)
}
} else {
log.Errorf("Broken uid: %v", err)
}
} else {
log.Errorf("Wrong user name for chown: %v", err)
}
}
}
return fmt.Sprintf("%s (%v kbytes) | %s", filepath.Base(src), file.Size/1024, link)
} }
func (c *Client) formatBantime(hours int64) int32 { func (c *Client) formatBantime(hours int64) int32 {
@ -573,44 +608,44 @@ func (c *Client) messageToText(message *client.Message, preview bool) string {
return fmt.Sprintf("unknown message (%s)", message.Content.MessageContentType()) return fmt.Sprintf("unknown message (%s)", message.Content.MessageContentType())
} }
func (c *Client) contentToFilename(content client.MessageContent) (*client.File, string) { func (c *Client) contentToFile(content client.MessageContent) *client.File {
if content == nil { if content == nil {
return nil, "" return nil
} }
switch content.MessageContentType() { switch content.MessageContentType() {
case client.TypeMessageSticker: case client.TypeMessageSticker:
sticker, _ := content.(*client.MessageSticker) sticker, _ := content.(*client.MessageSticker)
return sticker.Sticker.Sticker, "sticker.webp" return sticker.Sticker.Sticker
case client.TypeMessageVoiceNote: case client.TypeMessageVoiceNote:
voice, _ := content.(*client.MessageVoiceNote) voice, _ := content.(*client.MessageVoiceNote)
return voice.VoiceNote.Voice, fmt.Sprintf("voice note (%v s.).oga", voice.VoiceNote.Duration) return voice.VoiceNote.Voice
case client.TypeMessageVideoNote: case client.TypeMessageVideoNote:
video, _ := content.(*client.MessageVideoNote) video, _ := content.(*client.MessageVideoNote)
return video.VideoNote.Video, fmt.Sprintf("video note (%v s.).mp4", video.VideoNote.Duration) return video.VideoNote.Video
case client.TypeMessageAnimation: case client.TypeMessageAnimation:
animation, _ := content.(*client.MessageAnimation) animation, _ := content.(*client.MessageAnimation)
return animation.Animation.Animation, "animation.mp4" return animation.Animation.Animation
case client.TypeMessagePhoto: case client.TypeMessagePhoto:
photo, _ := content.(*client.MessagePhoto) photo, _ := content.(*client.MessagePhoto)
sizes := photo.Photo.Sizes sizes := photo.Photo.Sizes
if len(sizes) >= 1 { if len(sizes) >= 1 {
file := sizes[len(sizes)-1].Photo file := sizes[len(sizes)-1].Photo
return file, strconv.FormatInt(int64(file.Id), 10) + ".jpg" return file
} }
return nil, "" return nil
case client.TypeMessageAudio: case client.TypeMessageAudio:
audio, _ := content.(*client.MessageAudio) audio, _ := content.(*client.MessageAudio)
return audio.Audio.Audio, filepath.Base(audio.Audio.Audio.Local.Path) return audio.Audio.Audio
case client.TypeMessageVideo: case client.TypeMessageVideo:
video, _ := content.(*client.MessageVideo) video, _ := content.(*client.MessageVideo)
return video.Video.Video, filepath.Base(video.Video.Video.Local.Path) return video.Video.Video
case client.TypeMessageDocument: case client.TypeMessageDocument:
document, _ := content.(*client.MessageDocument) document, _ := content.(*client.MessageDocument)
return document.Document.Document, filepath.Base(document.Document.Document.Local.Path) return document.Document.Document
} }
return nil, "" return nil
} }
func (c *Client) messageToPrefix(message *client.Message, fileString string) string { func (c *Client) messageToPrefix(message *client.Message, fileString string) string {

View file

@ -146,8 +146,8 @@ func TestFormatContent(t *testing.T) {
}, },
} }
content := c.formatContent(&file, "a.jpg") content := c.formatFile(&file)
if content != "a.jpg (23 kbytes) | localhvost/b0896d9e9f1de7d2af59b080c3f0947b838c5c6c64f71c68a4b690a15de2ccf8.jpg" { if content != ". (23 kbytes) | " {
t.Errorf("Wrong file label: %v", content) t.Errorf("Wrong file label: %v", content)
} }
} }
@ -351,142 +351,6 @@ func TestMessageUnknown(t *testing.T) {
} }
} }
func TestContentToFilenameSticker(t *testing.T) {
sticker := client.MessageSticker{
Sticker: &client.Sticker{},
}
_, filename := (&Client{}).contentToFilename(&sticker)
if filename != "sticker.webp" {
t.Errorf("Wrong sticker filename")
}
}
func TestContentToFilenameVoice(t *testing.T) {
voice := client.MessageVoiceNote{
VoiceNote: &client.VoiceNote{
Duration: 56,
},
}
_, filename := (&Client{}).contentToFilename(&voice)
if filename != "voice note (56 s.).oga" {
t.Errorf("Wrong voice note filename")
}
}
func TestContentToFilenameVideoNote(t *testing.T) {
video := client.MessageVideoNote{
VideoNote: &client.VideoNote{
Duration: 56,
},
}
_, filename := (&Client{}).contentToFilename(&video)
if filename != "video note (56 s.).mp4" {
t.Errorf("Wrong video note filename")
}
}
func TestContentToFilenameAnimation(t *testing.T) {
animation := client.MessageAnimation{
Animation: &client.Animation{},
}
_, filename := (&Client{}).contentToFilename(&animation)
if filename != "animation.mp4" {
t.Errorf("Wrong animation filename")
}
}
func TestContentToFilenamePhoto(t *testing.T) {
photo := client.MessagePhoto{
Photo: &client.Photo{
Sizes: []*client.PhotoSize{
&client.PhotoSize{
Photo: &client.File{},
},
&client.PhotoSize{
Photo: &client.File{
Id: 56,
},
},
},
},
}
_, filename := (&Client{}).contentToFilename(&photo)
if filename != "56.jpg" {
t.Errorf("Wrong photo filename")
}
}
func TestContentToFilenamePhotoNoSizes(t *testing.T) {
photo := client.MessagePhoto{
Photo: &client.Photo{
Sizes: []*client.PhotoSize{},
},
}
_, filename := (&Client{}).contentToFilename(&photo)
if filename != "" {
t.Errorf("Wrong filename of sizeless photo")
}
}
func TestContentToFilenameAudio(t *testing.T) {
audio := client.MessageAudio{
Audio: &client.Audio{
FileName: "swine.mp3",
Audio: &client.File{
Local: &client.LocalFile{
Path: "C:/WINNT/swine.mp3",
},
},
},
}
_, filename := (&Client{}).contentToFilename(&audio)
if filename != "swine.mp3" {
t.Errorf("Not oinking, shame on you!")
}
}
func TestContentToFilenameVideo(t *testing.T) {
video := client.MessageVideo{
Video: &client.Video{
FileName: "swine.3gp",
Video: &client.File{
Local: &client.LocalFile{
Path: "C:/Document and Settings/Svinarchuk-PC/swine.3gp",
},
},
},
}
_, filename := (&Client{}).contentToFilename(&video)
if filename != "swine.3gp" {
t.Errorf("Not pigdancing, shame on you!")
}
}
func TestContentToFilenameDocument(t *testing.T) {
document := client.MessageDocument{
Document: &client.Document{
FileName: "swine.doc",
Document: &client.File{
Local: &client.LocalFile{
Path: "D:/My Documents/swine.doc",
},
},
},
}
_, filename := (&Client{}).contentToFilename(&document)
if filename != "swine.doc" {
t.Errorf("Not hoofstomping, shame on you!")
}
}
func TestContentToFilenameUnknown(t *testing.T) {
unknown := client.MessageExpiredPhoto{}
_, filename := (&Client{}).contentToFilename(&unknown)
if filename != "" {
t.Errorf("Wrong filename of unknown content")
}
}
func TestMessageToPrefix1(t *testing.T) { func TestMessageToPrefix1(t *testing.T) {
message := client.Message{ message := client.Message{
Id: 42, Id: 42,