package main import ( "bytes" "context" "fmt" "io" "math/big" "os" "github.com/dustin/go-humanize" "github.com/flytam/filenamify" "github.com/gotd/td/telegram/message" "github.com/gotd/td/telegram/uploader" "github.com/gotd/td/tg" ) type Uploader struct{} var dlUploader Uploader func (p Uploader) Chunk(ctx context.Context, state uploader.ProgressState) error { dlQueue.HandleProgressPercentUpdate(uploadStr, int(state.Uploaded*100/state.Total)) return nil } func (p *Uploader) UploadFile(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, f io.ReadCloser, format, title string, width, height int) error { // Get file size by seeking if it's a file var fileSize int64 if file, ok := f.(*os.File); ok { stat, err := file.Stat() if err != nil { return fmt.Errorf("getting file stat error: %w", err) } fileSize = stat.Size() if params.MaxSize > 0 && fileSize > params.MaxSize { return fmt.Errorf("file is too big, max. allowed size is %s", humanize.BigBytes(big.NewInt(int64(params.MaxSize)))) } } else { // Fallback: read to buffer for non-file readers return p.uploadFromBuffer(ctx, entities, u, f, format, title, width, height) } fmt.Println(" got", fileSize, "bytes, uploading...") dlQueue.currentlyDownloadedEntry.progressInfo = fmt.Sprint(" (", humanize.BigBytes(big.NewInt(fileSize)), ")") // Reset file pointer to beginning if _, err := f.(*os.File).Seek(0, 0); err != nil { return fmt.Errorf("seeking file error: %w", err) } // Use uploader.NewUpload with progress callback upload, err := telegramUploader.Upload(ctx, uploader.NewUpload("yt-dlp", f, fileSize)) if err != nil { return fmt.Errorf("uploading %w", err) } // Now we have uploaded file handle, sending it as styled message. First, preparing message. var document message.MediaOption filename, _ := filenamify.Filenamify(title+"."+format, filenamify.Options{Replacement: " "}) if format == "mp3" { document = message.UploadedDocument(upload).Filename(filename).Audio().Title(title) } else { doc := message.UploadedDocument(upload).Filename(filename).Video() // Set resolution to help Telegram display correct aspect ratio if width > 0 && height > 0 { doc = doc.Resolution(width, height) } document = doc } // Sending message with media. if _, err := telegramSender.Answer(entities, u).Media(ctx, document); err != nil { return fmt.Errorf("send: %w", err) } return nil } func (p *Uploader) uploadFromBuffer(ctx context.Context, entities tg.Entities, u *tg.UpdateNewMessage, f io.ReadCloser, format, title string, width, height int) error { // Fallback for non-file io.ReadCloser - read all to buffer buf := make([]byte, 0) tempBuf := make([]byte, 8192) for { n, err := f.Read(tempBuf) if err != nil && err != io.EOF { return fmt.Errorf("reading to buffer error: %w", err) } if n == 0 { break } buf = append(buf, tempBuf[:n]...) if params.MaxSize > 0 && len(buf) > int(params.MaxSize) { return fmt.Errorf("file is too big, max. allowed size is %s", humanize.BigBytes(big.NewInt(int64(params.MaxSize)))) } } fmt.Println(" got", len(buf), "bytes, uploading...") dlQueue.currentlyDownloadedEntry.progressInfo = fmt.Sprint(" (", humanize.BigBytes(big.NewInt(int64(len(buf)))), ")") // Use Upload with progress for buffer too upload, err := telegramUploader.Upload(ctx, uploader.NewUpload("yt-dlp", bytes.NewReader(buf), int64(len(buf)))) if err != nil { return fmt.Errorf("uploading %w", err) } var document message.MediaOption filename, _ := filenamify.Filenamify(title+"."+format, filenamify.Options{Replacement: " "}) if format == "mp3" { document = message.UploadedDocument(upload).Filename(filename).Audio().Title(title) } else { doc := message.UploadedDocument(upload).Filename(filename).Video() // Set resolution to help Telegram display correct aspect ratio if width > 0 && height > 0 { doc = doc.Resolution(width, height) } document = doc } if _, err := telegramSender.Answer(entities, u).Media(ctx, document); err != nil { return fmt.Errorf("send: %w", err) } return nil }