1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【DiscordGo】Embedにローカルの画像を添付する + 僕が詰まったこと

Last updated at Posted at 2024-12-23

目標

  • Embedにローカルで保存されている画像を使う

やること

  • メッセージが作成されたとき、ローカル画像を添付したEmbedを送信する

使うもの

  • Go
  • DiscordGo - Go言語でDiscord botを作るパッケージ

※環境構築は割愛

ディレクトリ構成

project_root/
  ├ main.go
  ├ utils
  │   └ file.go - package utils
  └ images
      ├ image_1.webp
      └ thumbnail_1.webp

要点

一部を抜粋しています。実装は次の見出しを参照

1. 作業ディレクトリを基準に画像への絶対パスを作る。

utils/file.go
// 現在の作業ディレクトリを取得
currentDir, err := os.Getwd()
if err != nil {
	return nil, "", "", fmt.Errorf("error getting current working directory: %w", err)
}

// 作業ディレクトリを基準にファイルの絶対パスを作成
log.Printf("cd: %s", currentDir)
absFilePath := fmt.Sprintf("%s/images/%s", currentDir, fileName)

Linuxのsystemdでbotを常駐させるときのWorkingDirectoryにあたります。

/etc/systemd/system/your_service.service
[Service]
WorkingDirectory=/home/your_user/project_root/

2. ファイルを読み込む

utils/fie.go
file, err := os.Open(absFilePath) // 生成した絶対パス
contentType := "image/webp"

3. 使用時に関数を呼び出す

4. discordgo.File{}を作る

main.go
// 1. *os.Fileを取得
imageFile, contentType, err := utils.PrepareFile(imageFileName)
if err != nil {
    log.Printf("Error preparing file: %v", err)
    return
}

// 2. discordgo.File{}を作成
imageDiscordFile := &discordgo.File{
    Name: imagePath, 
    ContentType:contentType, 
    Reader: imageFile,
}

5. s.ChannelMessageSendComplexを使って送信する

main.go
// 送信するデータを作成
sendData := &discordgo.MessageSend{
    Embed: embed,
    Files: []*discordgo.File{
    	imageDiscordFile,
    	thumbnailDiscordFile,
    },
}

// 送信
s.ChannelMessageSendComplex("your channelID", sendData)

普通のEmbedを送信する際のs.ChannelMessageSendEmbed()ではありません。

実装

以下の順に記載

  1. utils/file.go
  2. main.go
utils/file.go
package utils

// ファイルを*os.Fileとして返す関数
func PrepareFile(fileName string) (*os.File, string, string, error) {
	// 現在の作業ディレクトリを取得
	currentDir, err := os.Getwd()
	if err != nil {
		return nil, "", "", fmt.Errorf("error getting current working directory: %w", err)
	}

	// 作業ディレクトリを基準にファイルの絶対パスを作成
	log.Printf("cd: %s", currentDir)
	absFilePath := fmt.Sprintf("%s/images/%s", currentDir, fileName)

	// ファイルを開く
	file, err := os.Open(absFilePath)
	if err != nil {
		return nil, "", "", fmt.Errorf("error opening file: %w", err)
	} else {
		log.Printf("successful open file")
	}
 
    // Mineタイプを設定する。拡張子が複数ある時はここで条件分岐
	contentType := "image/webp"

	// *os.File, MIMEタイプを返す
	return file, contentType, nil
}
main.go
package main

func main() {
    // セッションを作成する
    session, err := discordgo.New("Bot " + "your token")
    // ...略

    // ハンドラを登録する
    // 第二引数でトリガーを指定(今回は「メッセージが作成されたとき」)
    session.AddHandler(func (s *discordgo.Session, m *discordgo.MessageCreate) {

        imageFileName := "image_1.webp"
        thumbnailFileName := "thumbnail_1.webp"

        // 1. *os.Fileを取得
    	imageFile, contentType, err := utils.PrepareFile(imageFileName)
    	if err != nil {
    		log.Printf("Error preparing file: %v", err)
    		return
    	}

        // 2. discordgo.File{}を作成
    	imageDiscordFile := &discordgo.File{
    		Name: imagePath, 
    		ContentType:contentType, 
    		Reader: imageFile,
    	}

        // 1. 以下同じ
    	thumbnailFile, contentType, err := utils.PrepareFile(thumbnailFileName)
    	if err != nil {
    		log.Printf("Error preparing file: %v", err)
    		return
    	}
     
        // 2
    	thumbnailDiscordFile := &discordgo.File{
    		Name: thumbnailPath, 
    		ContentType:contentType, 
    		Reader: thumbnailFile,
    	}
     
		embed := &discordgo.MessageEmbed{
    		Type: "rich",
    		Title: "タイトル"
    		Color: (255 << 16) | (255 << 8) | 0, // R|G|B のシフト演算で指定 
    		Image: &discordgo.MessageEmbedImage{
    			URL: fmt.Sprintf("attachment://%s", imageFileName),	// 本題
    		},
    		Thumbnail: &discordgo.MessageEmbedThumbnail{
    			URL: fmt.Sprintf("attachment://%s", thumbnailFileName), // 本題
    		},
    	}

        // 送信するデータを作成
        sendData := &discordgo.MessageSend{
    		Embed: embed,
    		Files: []*discordgo.File{
    			imageDiscordFile,
    			thumbnailDiscordFile,
    		},
    	}

        // 送信
        s.ChannelMessageSendComplex("your channelID", sendData)
        // × s.ChannelMessageSendEmbed()
})

    // ...略
     
}

筆者が遭遇したエラー

*bytes.Bufferを使わない

はじめ、PrepareFile()では*bytes.Bufferを返していた。

discordgo.File{}の定義
// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

Reader*bytes.Bufferを渡してもエラーは発生しないが、Embedに画像が表示されなかった。PrepareFile()の戻り値を*os.FileにしてReaderに渡したところ、画像が表示された。chatGPTなどがBufferを使ったコードを書くことがあるので、画像が表示されない場合は注意してほしい。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?