Files
nostr-webhost/hostr/cmd/deploy/media.go
2023-10-24 23:15:41 +09:00

197 lines
4.2 KiB
Go

package deploy
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"strings"
"sync"
"github.com/nbd-wtf/go-nostr"
"github.com/studiokaiji/nostr-webhost/hostr/cmd/tools"
)
var availableContentTypes = []string{
"image/png",
"image/jpg",
"image/jpeg",
"image/gif",
"image/webp",
"video/mp4",
"video/quicktime",
"video/mpeg",
"video/webm",
"audio/mpeg",
"audio/mpg",
"audio/mpeg3",
"audio/mp3",
}
var availableContentSuffixes = []string{
".png",
".jpg",
".jpeg",
".gif",
".webp",
".mp4",
".quicktime",
".mpeg",
".webm",
".mpeg",
".mpg",
".mpeg3",
".mp3",
}
var availableMediaHtmlTags = []string{
"img",
"audio",
"video",
"source",
"object",
"embed",
}
func isValidMediaFileType(path string) bool {
for _, suffix := range availableContentSuffixes {
if strings.HasSuffix(path, suffix) {
return true
}
}
return false
}
const uploadEndpoint = "https://nostrcheck.me/api/v1/media"
type MediaResult struct {
result bool
description string
status string
id int
pubkey string
url string
hash string
magnet string
tags []string
}
var mediaUploadRequestQueue []func() (*MediaResult, error)
func addNostrEventQueue(event *nostr.Event) {
nostrEventsQueue = append(nostrEventsQueue, event)
}
func addMediaUploadRequestFuncQueue(reqFunc func() (*MediaResult, error)) {
mediaUploadRequestQueue = append(mediaUploadRequestQueue, reqFunc)
}
var allRelays []string
func uploadMediaFilesFromQueue() {
// Publishの進捗状況を表示
allEventsCount := len(mediaUploadRequestQueue)
uploadedFilesCount := 0
var wg sync.WaitGroup
go func() {
wg.Add(1)
tools.DisplayProgressBar(&uploadedFilesCount, &allEventsCount)
wg.Done()
}()
var mutex sync.Mutex
// アップロードを並列処理
for _, reqFunc := range mediaUploadRequestQueue {
wg.Add(1)
go func(reqFun func() (*MediaResult, error)) {
_, err := reqFun()
if err != nil {
fmt.Println(err)
return
}
mutex.Lock() // ロックして排他制御
uploadedFilesCount++ // カウントアップ
mutex.Unlock() // ロック解除
wg.Done() // ゴルーチンの終了を通知
}(reqFunc)
}
wg.Wait()
}
func filePathToUploadMediaRequest(filePath, priKey, pubKey string) (*http.Request, error) {
// ファイルを開く
file, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("Failed to read %s: %w", filePath, err)
}
defer file.Close()
// リクエストボディのバッファを初期化
var requestBody bytes.Buffer
// multipart writerを作成
writer := multipart.NewWriter(&requestBody)
// uploadtypeフィールドを設定
err = writer.WriteField("uploadtype", "media")
if err != nil {
return nil, fmt.Errorf("Error writing field: %w", err)
}
// mediafileフィールドを作成
part, err := writer.CreateFormFile("mediafile", filePath)
if err != nil {
return nil, fmt.Errorf("Error creating form file: %w", err)
}
// ファイルの内容をpartにコピー
_, err = io.Copy(part, file)
if err != nil {
return nil, fmt.Errorf("Error copying file: %w", err)
}
// writerを閉じてリクエストボディを完成させる
err = writer.Close()
if err != nil {
return nil, fmt.Errorf("Error closing writer: %w", err)
}
// タグを初期化
tags := nostr.Tags{}
// タグを追加
tags.AppendUnique(nostr.Tag{"u", uploadEndpoint})
tags.AppendUnique(nostr.Tag{"method", "POST"})
tags.AppendUnique(nostr.Tag{"payload", ""})
// イベントを生成
ev, err := getEvent(priKey, pubKey, "", 27533, tags)
if err != nil {
return nil, fmt.Errorf("Error get event: %d", err)
}
// イベントをJSONにマーシャル
evJson, err := ev.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("Error marshaling event: %d", err)
}
// HTTPリクエストを作成
request, err := http.NewRequest("POST", uploadEndpoint, &requestBody)
if err != nil {
return nil, fmt.Errorf("Error creating request: %d", err)
}
// ヘッダーを設定
request.Header.Set("Content-Type", writer.FormDataContentType())
request.Header.Set("Authorization", "Nostr "+base64.StdEncoding.EncodeToString(evJson))
request.Header.Set("Accept", "application/json")
return request, nil
}