Move downloaded files to a permanent location
This commit is contained in:
parent
4307f85a04
commit
699d75552a
|
@ -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/'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
},
|
},
|
||||||
":upload": {
|
":upload": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
":user": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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,
|
if c.content.Path != "" && c.content.Link != "" {
|
||||||
c.formatFilePath(c.content.Link, file.Remote.UniqueId, filepath.Ext(file.Local.Path)),
|
src = file.Local.Path // source path
|
||||||
)
|
_, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) formatFilePath(basedir string, id string, ext string) string {
|
basename := file.Remote.UniqueId + filepath.Ext(src)
|
||||||
return fmt.Sprintf("%s/%x%s", basedir, sha256.Sum256([]byte(id)), ext)
|
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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue