Python

【Python】LINEのAPIでリッチメニュー表示をユーザーごとに切り分ける

この記事は約12分で読めます。

 

こんにちは、ミナピピン(@python_mllover)です!

 

今回は仕事でLINEのAPIを使って表示されるリッチメニューをユーザーごとに分けてほしいという依頼を頂いてその調査結果をメモとしてまとめておこうと思います。

 

具体的にはGoogle先生で「line api リッチメニュー python」みたいなワードでググると以下のサイトがヒットするのですが、か書かれたのが2017年で情報が古くコードが動かなくなっていたのでAPIドキュメントを見て書き直しました。

 

参考サイト:https://qiita.com/uezo/items/2dd9db3046ef7b28ed2e

 

前提となるAPIのチャンネルの作成やアクセストークンやシークレットトークンの確認方法については特に変わっていないので、上の記事や以下の参考書籍を参考にしてください。

 

 

 

クラス定義&初期設定

 

まずはクラス定義の部分で、APIのURLとかリクエスト形式が変わっていて実行するとエラーを吐いていたので書き直して、追加で今回の作業に最低限必要な機能だけ関数として付け加えました。

 

class RichMenu:
    def __init__(self, name, chat_bar_text, size_full=True, selected=False):
        self.size = {"width": 2500, "height": 1686}
        if not size_full:
            self.size["height"] = 843
        self.selected = selected
        self.name = name
        self.chat_bar_text = chat_bar_text
        self.areas = []

    def add_area(self, x, y, width, height, action_type, payload):
        bounds = {"x": x, "y": y, "width": width, "height": height}
        action = {"type": action_type}
        if action_type == "postback":
            if isinstance(payload, list):
                action["data"] = payload[0]
                if len(payload) > 1:
                    action["text"] = payload[1]
            else:
                action["data"] = payload
        elif action_type == "uri":
            action["uri"] = payload
        else:
            action["text"] = payload
        self.areas.append({"bounds": bounds, "action": action})

    def to_json(self):
        dic = {"size": self.size, "selected": self.selected, "name": self.name, "chatBarText": self.chat_bar_text, "areas": self.areas}
        return json.dumps(dic)
        


class RichMenuManager:
    def __init__(self, channel_access_token, verify=True):
        self.headers = {"Authorization": "Bearer {%s}" % channel_access_token}
        self.verify = verify

    def register(self, rich_menu, image_path=None):
        url = "https://api.line.me/v2/bot/richmenu"
        res = requests.post(url, headers=dict(self.headers, **{"content-type": "application/json"}), data=rich_menu.to_json(), verify=self.verify).json()
        print(res)
        if image_path:
            up_res = self.upload_image(res["richMenuId"], image_path)
            if up_res == {}:
                print(up_res,'画像をアップロードに成功しました!')
        return res

    def upload_image(self, rich_menu_id, image_path):
        url = "https://api-data.line.me/v2/bot/richmenu/%s/content" % rich_menu_id
        image_file = open(image_path, "rb")
        headers=dict(self.headers, **{"content-type": "image/jpeg"})
        print('json',headers)
        return requests.post(url, headers=headers, data=image_file, verify=self.verify).json()

    def download_image(self, richmenu_id, filename=None):
        url = "https://api.line.me/v2/bot/richmenu/%s/content" % richmenu_id
        res = requests.get(url, headers=self.headers, verify=self.verify)
        print('dl',res)
        if filename:
            with open(filename, "wb") as f:
                f.write(res.content)
        else:
            return res.content

    def get_list(self):
        url = "https://api.line.me/v2/bot/richmenu/list"
        return requests.get(url, headers=self.headers, verify=self.verify).json()

    def remove(self, richmenu_id):
        url = "https://api.line.me/v2/bot/richmenu/%s" % richmenu_id
        return requests.delete(url, headers=self.headers, verify=self.verify).json()


    def remove_all(self):
        menus = self.get_list()
        for m in menus["richmenus"]:
            self.remove(m["richMenuId"])

    def apply(self, user_id, richmenu_id):
        url = "https://api.line.me/v2/bot/user/%s/richmenu/%s" % (user_id, richmenu_id)
        print(url)
        return requests.post(url, headers=self.headers, verify=self.verify).json()
    
    def set_default(self, richmenu_id):
        url = "https://api.line.me/v2/bot/user/all/richmenu/%s" % (richmenu_id)
        print(url)
        return requests.post(url, headers=self.headers, verify=self.verify).json()
    
    def get_default(self):
        url = "https://api.line.me/v2/bot/user/all/richmenu"
        return requests.get(url, headers=self.headers, verify=self.verify).json()


    def detach(self, user_id):
        url = "https://api.line.me/v2/bot/user/%s/richmenu" % user_id
        return requests.delete(url, headers=self.headers, verify=self.verify).json()

    def get_applied_menu(self, user_id):
        url = "https://api.line.me/v2/bot/user/%s/richmenu" % user_id
        return requests.get(url, headers=self.headers, verify=self.verify).json()



 

ここからはコードを実行してAPI経由でリッチメニューを設定していきます。

 

# 初期設定&インスタンス作成
channel_access_token = "自分のアクセストークン"
rmm = RichMenuManager(channel_access_token)

 

とりあえず4分割画面のリッチメニューを設定します。

 

rm = RichMenu(name="Test menu", chat_bar_text="Open this menu")
rm.add_area(0, 0, 1250, 843, "message", "質問があります")
rm.add_area(1250, 0, 1250, 843, "uri", "http://imoutobot.com")
rm.add_area(0, 843, 1250, 843, "postback", "data1=from_richmenu&data2=as_postback")
rm.add_area(1250, 843, 1250, 843, "postback", ["data3=from_richmenu_with&data4=message_text", "ポストバックのメッセージ"])

# リッチメニューの画像を登録する
res = rmm.register(rm, r"path/to/〇〇.jpg")
richmenu_id = res["richMenuId"]
print("Registered as " + richmenu_id)

 

リッチメニューに登録する画像はサイズ制限やピクセル制限・アスペクト比制限があるのでそれらをクリアするものにしてください。

 

そしてレスポンスでリッチメニューIDが返ってきています。このIDを使ってデフォルト表示のリッチメニューやユーザーごとの個別リッチメニューを設定していきます。

 

 

スポンサーリンク
スポンサーリンク

ユーザーごとに個別のリッチメニューの設定する

 

いよいよ本題のユーザーごとのリッチメニュー設定に入っていきます。まずデフォルトのリッチメニューの設定は以下のコードを実行するだけです。

 

# デフォルトのリッチメニューを設定する
rmm.set_default(richmenu_id)

 

そして、ユーザーごとのリッチメニュー設定は以下のコードになります。

 

# ユーザーごとに個別のリッチメニューを設定する
user_id = "ユーザーの内部ID"
rmm.apply(user_id, richmenu_id)

 

ここで注意なのはLINEのアプリに表示されているユーザIDを指定すると{‘message’: “The value for the ‘userId’ parameter is invalid”}というエラーが返ってくるので、引数のユーザーIDはLINEのアプリ上に表示されるIDではなく内部ID(mid)と呼ばれる16進数のユニークな数字ないといけないという点。正直コード作成よりもこの内部ユーザーIDの把握に手間取りました。

 

内部ユーザーIDの確認方法についてはherokuでwebhook URL用のサーバーを立ち上げてそこに送られてくるレスポンスで確認するしかないと思うのですが、結構手間が掛かるので別記事で紹介したいと思います。では~

 

関連記事:

 

 

 

 

コメント

タイトルとURLをコピーしました