🤖

ブラウザから1クリックでSlackに投稿できるようにした

2024/12/11に公開

こんにちは、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-NAMEHTTP-TRIGGERは適宜修正してください。

処理の内容は、

  • 変数t,u,nを宣言します。
  • tに閲覧中のWebページのタイトルを代入します。
  • uに閲覧中のWebページのURLを代入します。
  • nにGETメソッドのパラメータ(tu)を含めた遷移先の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.txtrequestsを追記するのとAzure-Functions-Environment-Variables-Settingを設定するのをお忘れなく。

Azure FunctionsのHttpResponseクラスについてはこちらで調べました

最後に

こんな記事を書いていると、普段どんな業務をしているのか想像できない、と思われそうです。この記事で書いたことは趣味3分の1実用3分の1勢い3分の1で、普段の業務とは全く関係ありません。普段はマジメにお仕事している...つもりです、そのハズです。(弱気)。

TRUSTDOCK テックブログ

Discussion