ブラウザから1クリックでSlackに投稿できるようにした
こんにちは、TRUSTDOCKのよもぎたです。
はじめに
ニュースやZennの記事、ブログエントリなどをSlackで共有したいと思ったことはありませんか?私はよくあります。そこで、Webブラウザから1クリックで閲覧中のページをSlackに投稿できる仕組みを作りました。この記事ではその仕組みを紹介させていただきます。
謝辞
このアイディアは、技術書典で出会った増井技術士事務所さんの「ブックマークレット32本ノック」という本から着想を得ています。この場を借りて深く感謝申し上げます。
概要
この仕組みは、Webブラウザのブックマーク/お気に入りに登録したブックマークレットを利用して閲覧中のページのタイトルとURLを取得してSlackに投稿します。しかし、閲覧中のページとSlackのWebhookはオリジンが異なるため、ブックマークレットから直接SlackのWebhookに通信=投稿することはできません。そこで、一度Azure Functionsを経由してWebhookにPOSTしています。
一言で経由と書きましたが、より詳しくは、
- ブックマークレットのJavaScriptで閲覧中のページのタイトルとURLを取得します。
- ブックマークレットのJavaScriptで閲覧中のページからAzure FunctionsのURLに遷移させます。その際、GETメソッドでページのタイトルとURLをAzure Functionsに渡します。
- Azure Functionsが受け取ったページのタイトルとURLをもとにメッセージを組み立ててSlackのIncoming WebhookにPOSTします。
ということをしています。
要は、この記事の左側にある「Xに投稿」ボタンと同じような仕組みです。リンクがないならブックマークレットで作ればいいじゃない。Incoming Webhookにパラメータが渡せないならAzure Functionsを使えばいいじゃない。言ってしまえばそれだけです。
なお、Azure Functionsを使っているのは私がかじったことがあるからです。
多分、AWS Lambdaでも同じことが出来ます。知らんけど。(言ってみたかった。私は関東出身で関東以外に住んだことはありません。)
実装の一例
ブックマークレット
ブックマークレットはJavaScriptのワンライナーで書きます。書き方のノウハウは上記の「ブックマークレット32本ノック」で覚えました。「これどういうこと?」という書き方があれば、ぜひ同書をお読みください。
さて、作成したブックマークレットは下記のようなものです。
javascript:((d)=>{let t,u,n;t=d.title;u=d.location.href;n=encodeURI("https://FUNCTION-NAME.azurewebsites.net/api/HTTP-TRIGGER?title="+t+"&url="+u);location.href=n;})(document);
FUNCTION-NAME
とHTTP-TRIGGER
は適宜修正してください。
処理の内容は、
- 変数
t,u,n
を宣言します。 -
t
に閲覧中のWebページのタイトルを代入します。 -
u
に閲覧中のWebページのURLを代入します。 -
n
にGETメソッドのパラメータ(t
とu
)を含めた遷移先のURLをencodeURI()
して代入します。 - 最後に
n
にページ遷移しています。
ワンライナーなのでエラー処理は省いています。
実際は、もう少し変数と処理を増やして、prompt()
を使って一言付け加えられるようにしていたり、POST先のワークスペースやチャンネルを選択できるようにしています。つまり、コメントの有無やPOST先のワークスペースやチャンネルの数だけブックマークレットが増えます。
ブラウザの様子をチラ見せするとこんな感じになっています。
Azure Functions
Azure FunctionsはPythonで書きました。これまた、かじったことがあるからです。
import azure.functions as func
import logging
import os
import requests
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@app.route(route="HTTP-TRIGGER")
def HTTP-TRIGGER(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
title = req.params.get('title')
url = req.params.get('url')
post_webhook = os.getenv('Azure-Functions-Environment-Variables-Setting')
icon = 'お好みでアイコンを設定'
username = 'お好みでユーザー名を設定'
if url:
text = f'<{url}|{title}>'
payload_text = {'text': text}
payload_icon = {'icon_emoji': f':{icon}:'}
payload_username = {"username": username}
payload = {**payload_text, **payload_icon, **payload_username}
requests.post(post_webhook, json=payload)
return func.HttpResponse(
f"<html lang=ja><head><meta http-equiv='refresh' content='5;URL={url}'</head><body>title: {title}<br>\nurl: {url}<br>\nworkspace: {workspace}<br>\n<a href={url}>元のページに戻る</a><body><html>",
headers = {'Content-Type': 'text/html; charset=utf-8'},
status_code = 200
)
else:
return func.HttpResponse('ブックマークレットからアクセスしてください', status_code = 200)
こちらもHTTP-TRIGGER
は適宜修正してください。さらにエラーハンドリングも手抜きです。あくまで一例ということで。
VSCodeにAzure関連の拡張を追加して、Azure Functionsのひな型を作るのがお勧めです。
「あ、こうすればいいんだな」と分かるコードを生成してくれます。
上記のHTTP-TRIGGER
もVSCode拡張がよしなに設定してくれます。
requirements.txt
にrequests
を追記するのとAzure-Functions-Environment-Variables-Setting
を設定するのをお忘れなく。
Azure FunctionsのHttpResponse
クラスについてはこちらで調べました。
最後に
こんな記事を書いていると、普段どんな業務をしているのか想像できない、と思われそうです。この記事で書いたことは趣味3分の1実用3分の1勢い3分の1で、普段の業務とは全く関係ありません。普段はマジメにお仕事している...つもりです、そのハズです。(弱気)。
Discussion