## 概要
[[Slack Web API]]で[[MP4]]ファイルなどの動画をスマートにアップロードする方法が、ドキュメントを見たり調べた限りだとよく分からない。事実を記録している。
## 公式クライアントの挙動
mp4ファイルをD&Dしたときの挙動。
### アップロード先URLの取得
```http
POST https://xxx.slack.com/api/files.getUploadURL?_x_id=99be626d-1712389821.855&_x_csid=fgNfxlapd2M&slack_route=TXXXXXXXX&_x_version_ts=1712363845&_x_frontend_build_type=current&_x_desktop_ia=4&_x_gantry=true&fp=92
```
```json
{
"ok": true,
"file": "F06SP7J72JK",
"upload_url": "https:\/\/files.slack.com\/upload\/v1\/CwABAAAAWAoAAdP0kn6O2wn5CgACF8OheGhrWvAMAAMLAAEAAAAJVDE5NENIWDhSCwACAAAACVUxREZFQlhWMwsAAwAAAAtGMDZTUDdKNzJKSwAKAAQAAAAAAAlEGAALAAIAAAAUdaTPph-EUtwh2fKDBE3b9sgM8c8A"}
```
### アップロード
```http
POST https://files.slack.com/upload/v1/CwABAAAAWAoAAdP0kn6O2wn5CgACF8OheGhrWvAMAAMLAAEAAAAJVDE5NENIWDhSCwACAAAACVUxREZFQlhWMwsAAwAAAAtGMDZTUDdKNzJKSwAKAAQAAAAAAAlEGAALAAIAAAAUdaTPph-EUtwh2fKDBE3b9sgM8c8A?client_context_team_id=TXXXXXXXX
```
```
OK - 607256
```
```http
POST https://xxx.slack.com/api/files.completeUpload?_x_id=99be626d-1712389823.269&_x_csid=fgNfxlapd2M&slack_route=TXXXXXXXX&_x_version_ts=1712363845&_x_frontend_build_type=current&_x_desktop_ia=4&_x_gantry=true&fp=92
```
```json
{"ok":true,"files":[{"id":"F06SP7J72JK","title":"2024-04-03_22h59_00.mp4"}]}
```
```http
POST https://xxx.slack.com/api/files.info?_x_id=99be626d-1712389825.506&_x_csid=fgNfxlapd2M&slack_route=TXXXXXXXX&_x_version_ts=1712363845&_x_frontend_build_type=current&_x_desktop_ia=4&_x_gantry=true&fp=92
```
```json
{
"ok": true,
"file": {
"id": "F06SP7J72JK",
"created": 1712389821,
"timestamp": 1712389821,
"name": "2024-04-03_22h59_00.mp4",
"title": "2024-04-03_22h59_00.mp4",
"mimetype": "video\/mp4",
"filetype": "mp4",
"pretty_type": "MPEG 4 Video",
"user": "U1DFEBXV3",
"user_team": "TXXXXXXXX",
"editable": false,
"size": 607256,
"mode": "hosted",
"is_external": false,
"external_type": "",
"is_public": false,
"public_url_shared": false,
"display_as_bot": false,
"username": "",
"transcription": {
"status": "processing"
},
"mp4": "https:\/\/files.slack.com\/files-tmb\/TXXXXXXXX-F06SP7J72JK-7cdff2a2ef\/2024-04-03_22h59_00.mp4",
"url_private": "https:\/\/files.slack.com\/files-tmb\/TXXXXXXXX-F06SP7J72JK-7cdff2a2ef\/2024-04-03_22h59_00.mp4",
"url_private_download": "https:\/\/files.slack.com\/files-pri\/TXXXXXXXX-F06SP7J72JK\/download\/2024-04-03_22h59_00.mp4",
"media_display_type": "video",
"thumb_video": "https:\/\/files.slack.com\/files-tmb\/TXXXXXXXX-F06SP7J72JK-7cdff2a2ef\/2024-04-03_22h59_00_thumb_video.jpeg",
"thumb_video_w": 996,
"thumb_video_h": 880,
"permalink": "https:\/\/xxx.slack.com\/files\/U1DFEBXV3\/F06SP7J72JK\/2024-04-03_22h59_00.mp4",
"permalink_public": "https:\/\/slack-files.com\/TXXXXXXXX-F06SP7J72JK-c4ec8b2c72",
"is_starred": false,
"shares": {},
"channels": [],
"groups": [],
"ims": [],
"has_more_shares": false,
"has_rich_preview": false,
"file_access": "visible",
"comments_count": 0
},
"comments": [],
"paging": {
"count": 500,
"total": 0,
"page": 1,
"pages": 0
}
}
```
### 投稿
```http
POST https://xxx.slack.com/api/files.share?_x_id=99be626d-1712390227.182&_x_csid=z8aeBUm8uB4&slack_route=TXXXXXXXX&_x_version_ts=1712363845&_x_frontend_build_type=current&_x_desktop_ia=4&_x_gantry=true&fp=92
draft_id: Dr06T3Q1GH7C
files: F06SP7J72JK
channel: C27UF296K
broadcast: false
client_msg_id: 8d16186c-3520-4998-9b2f-c92951573206
blocks: [{"type":"rich_text","elements":[{"type":"rich_text_section","elements":[{"type":"text","text":"hoge"}]}]}]
resharing_aware: true
skip_dlp_user_warning: false
from_share_modal: false
unfurl: []
client_context_team_id: TXXXXXXXX
```
```json
{"ok":true,"file_msg_ts":"1712390227.555439"}
```
## channel未指定アップロードを試す
```http
POST https://slack.com/api/files.upload
// fileのみを指定
```
```json
{
"ok": true,
"file": {
"id": "F06TSM1RL4Q",
"created": 1712395309,
"timestamp": 1712395309,
"name": "2024-04-06_18h20_50.mp4",
"title": "2024-04-06 18h20 50",
"mimetype": "video\/mp4",
"filetype": "mp4",
"pretty_type": "MPEG 4 Video",
"user": "U1DFEBXV3",
"user_team": "TXXXXXXXX",
"editable": false,
"size": 17109,
"mode": "hosted",
"is_external": false,
"external_type": "",
"is_public": false,
"public_url_shared": false,
"display_as_bot": false,
"username": "",
"url_private": "https:\/\/files.slack.com\/files-pri\/TXXXXXXXX-F06TSM1RL4Q\/2024-04-06_18h20_50.mp4",
"url_private_download": "https:\/\/files.slack.com\/files-pri\/TXXXXXXXX-F06TSM1RL4Q\/download\/2024-04-06_18h20_50.mp4",
"media_display_type": "video",
"thumb_video": "https:\/\/files.slack.com\/files-tmb\/TXXXXXXXX-F06TSM1RL4Q-9dd1a81a68\/2024-04-06_18h20_50_thumb_video.jpeg",
"thumb_video_w": 384,
"thumb_video_h": 322,
"permalink": "https:\/\/xxx.slack.com\/files\/U1DFEBXV3\/F06TSM1RL4Q\/2024-04-06_18h20_50.mp4",
"permalink_public": "https:\/\/slack-files.com\/TXXXXXXXX-F06TSM1RL4Q-6c481581ff",
"comments_count": 0,
"is_starred": false,
"shares": {},
"channels": [],
"groups": [],
"ims": [],
"has_more_shares": false,
"has_rich_preview": false,
"file_access": "visible"
}
}
```
以下のリクエストで投稿。
```console
curl 'https://slack.com/api/chat.postMessage' \
-H 'accept: */*' \
-H 'accept-language: ja,en-US;q=0.9,en;q=0.8' \
-H 'authorization: Bearer xoxp-xxxxxxxxxxxxxxxxxxxxxxxx' \
-H 'content-type: application/json;charset=utf-8' \
-H 'cookie: xxxx
-H 'origin: chrome-extension://cgclgomkfeiepcgolbdflhoddnenimbc' \
-H 'sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "Windows"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: none' \
-H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36' \
--data-raw '{"channel":"C27UF296K","blocks":[{"type":"section","text":{"type":"mrkdwn","text":"test2"}},{"type":"file","external_id":"F06T3TYHFL2","source":"remote"},{"type":"divider"},{"type":"context","elements":[{"type":"image","image_url":"https://github.com/tadashi-aikawa/fenice/raw/master/public/icon/384.png","alt_text":"fenice"},{"type":"mrkdwn","text":"Posted via Fenice"}]}]}'
```
bot_userのエラー?
```error
{"ok":false,"error":"no_bot_user"}
```
## no_bot_userの謎に迫る
調べてる限りだと原因はイマイチ分からない。。[[ChatGPT Plus]]に聞いてみた感じだと別のアプローチをとったほうがよさそう。
## permalinkを展開する
単に動画が共有できればいいのなら、permalinkを本文に貼り付けるのが一番楽。`mrkdwn`で空白文字に対してリンクを埋め込むことにより、文字は登場せずメディアを埋め込める。
```json
{
"channel": "#test_tadashi-aikawa",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "てすと"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<https://xxx.slack.com/files/U1DFEBXV3/F06TSM1RL4Q/2024-04-06_18h20_50.mp4| >"
}
}
]
}
```
## backup
```ts
const videoBlocks: VideoBlock[] = files.value
.filter((x) => x.type === "video")
.map((x) => ({
type: "video",
alt_text: "video",
title: {
type: "plain_text",
text: "Pasted video",
emoji: false,
},
thumbnail_url: x.thumbnail!,
video_url: x.url!,
}));
```