0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Node.js(TypeScript)でmixi APIを使って画像付きでツイートするメモ

Posted at

はじめに

ここまで来たら、mixi APIも調べてみようと思いましたが、意外と大変でした。何度も心がくじけそうになりました。

手順

1.ディベロッパー登録

まず大変だったのがクレジットカードの登録。クレジットカードの登録をしないと先に進めません。バーチャルカードは使用できませんでした。さらに、一日一回しか登録できないので、失敗すると次の日まで待たないといけないため、心がくじけそうになります。

2.アプリケーションの登録

アプリケーションを登録する際には、リダイレクトURLも記入してください。特にリダイレクト用のURLを用意しなくても、例えば「http://www.mztm.jp/redirect」のようなURLで大丈夫です。

consumer keyとconsumer secretを環境変数にでも入れておきましょう。

.env
MIXI_CONSUMER_KEY=aaaaaaaa
MIXI_CONSUMER_SECRET=bbbbbbbbbb

3.server stateの取得
ここからは時間との勝負です。

ここからは時間との勝負です。まずはServer Stateを取得しましょう。Server Stateとは...あー、このコードの有効時間は30分です。のんきに調べていたらコードが無効になってしまいますので急ぎましょう。

private getServerState = async (): Promise<any> => {
        const param = new URLSearchParams({
            grant_type: "server_state",
            client_id: process.env.MIXI_CONSUMER_KEY,
        });
        const headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        };

        try {
            const response = await axios.post("https://secure.mixi-platform.com/2/token", param, {headers})
            console.log(response.data.server_state)
        } catch (e) {
            console.log("error")
        }
    }

ここで出力されるのがServer Stateです。仮にcccccccと出力されたとしましょう。

4.OAuth Codeの取得

以下のようにURLを生成して、ブラウザに入力します。

const param = "client_id=" + process.env.MIXI_CONSUMER_KEY +
            "&response_type=code" +
            "&scope=w_voice" +
            "&display=pc" +
            "&server_state=ccccccc"
const url = "https://mixi.jp/connect_authorize.pl?" + param;
console.log(url)

許可をすると、上のリダイレクトURLにページ遷移します。
そのURLのアドレスからcodeの変数を取得します。
例:http://www.mztm.jp/redirect?code=ddddddddd
このdddddddddがOAuth Codeです。
OAuth Codeとは・・・
あー!OAuth Codeの有効時間は3分です。
ささ、急ぎましょう。

5.Tokenの取得

Server StateとOAuth Codeを使って、Tokenを取得します。

public getToken = async (): Promise<any> => {
        const server_state:string = "ccccccc";
        const code:string = "ddddddddd";
        const param = new URLSearchParams({
            grant_type: "authorization_code",
            client_id: process.env.MIXI_CONSUMER_KEY,
            client_secret: process.env.MIXI_CONSUMER_SECRET,
            code: code,
            server_state: server_state
        });

        const headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        };
        try {
            const response = await axios.post("https://secure.mixi-platform.com/2/token", param, {headers})
            console.log(response.data);
        } catch (e) {
            console.log("error")
        }
    }

以上を実行すると、出力されるはずです。

refresh_token: 'eeeeeeee',
expires_in: 900,
access_token: 'ffffffffffff',
token_type: 'Bearer',
scope: 'w_voice'

このaccess_tokenは900秒です。
ただ、今回は900秒を超えてしまっても、refresh_tokenを使って再度access_tokenを取得することができます。
refresh_tokenを環境変数に入れておきます。

.env
MIXI_REFRESH_TOKEN=eeeeeeee 

6.投稿

下準備はおわりました。
このrefresh tokenを使って投稿ごとにtokenを取得して、メッセージを投稿しましょう。
とりあえず画像付きの関数と画像なしの関数を用意しています。
それぞれ、まずはrefresh tokenを使い、access tokenを取得して、POSTにくっつけて送ります。

    private refreshToken = async () => {
        const date = {
            grant_type: "refresh_token",
            client_id: process.env.MIXI_CONSUMER_KEY,
            client_secret: process.env.MIXI_CONSUMER_SECRET,
            refresh_token: process.env.MIXI_REFRESH_TOKEN
        }
        const param = new URLSearchParams(date);
        const headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        };
        try {
            const response = await axios.post("https://secure.mixi-platform.com/2/token", param, {headers})

            return {
                data: {
                    success: true,
                    access_token: response.data.access_token
                }
            }
        } catch (e) {
            console.log("error " + e)
            return {
                data: {
                    success: false,
                }
            }
        }
    }

    
/**
 * メッセージをMixi APIを使用して送信します
 *
 * @param {string} message - 送信するメッセージ
 * @returns {Promise<any>} - 成功ステータスを含むオブジェクトを返すPromise
 * @throws {Error} - 送信プロセス中に失敗した場合、エラーを投げます
 */
    public send = async (message: string):Promise<any> => {
        const response: any = await this.refreshToken();
        if (response.data.success) {
            const param = new URLSearchParams({
                status: message,
                oauth_token: response.data.access_token
            });
            const headers = {
                'Content-Type': 'application/x-www-form-urlencoded'
            };
            try {
                await axios.post("https://api.mixi-platform.com/2/voice/statuses/update", param, {headers})
                return {
                    data:{
                        success: true
                    }
                }
            } catch (e) {
                console.log("error send!")
                return {
                    data:{
                        success: false,
                        error:{
                            message:e
                        }
                    }
                }
            }
        }
    }

/**
 * 画像をメッセージと一緒にMixiプラットフォームに送信します
 *
 * @param {string} message - 画像と一緒に送信するメッセージ
 * @param {string} imagePath - 画像ファイルへのパス
 * @returns {Promise<any>} - 成功ステータスとオプションのエラーメッセージを含むオブジェクトを返すPromise
 * @throws {Error} - 画像の読み取りまたは送信中にエラーが発生した場合、エラーを投げます
 */
    public sendEmbedImage = async (message: string, imagePath: string): Promise<any> => {
        const response: any = await this.refreshToken();
        if (response.data.success) {
            let photoData: Buffer;
            let contentType: string;
            if (imagePath.endsWith('.jpg') || imagePath.endsWith('.jpeg')) {
                contentType = 'image/jpeg';
            } else if (imagePath.endsWith('.png')) {
                contentType = 'image/png';
            } else {
                console.log("Unsupported image format");
                return;
            }

            try {
                const filePath = path.join(__dirname, imagePath);
                photoData = await fs.readFile(filePath);
                const headers = {
                    'Content-Type': contentType
                };
                const url: string = `https://api.mixi-platform.com/2/voice/statuses/update?status=${encodeURIComponent(message)}&oauth_token=${response.data.access_token}`;
                await axios.post(url, photoData, {headers});
                return {
                    data:{
                        success:true
                    }
                }
            } catch (e) {
                console.log("error " + e);
                return {
                    data:{
                        success: false,
                        error:{
                            message:e
                        }
                    }
                }
            }
        }
    }


まとめ

あー、疲れました。
もう少しきれいな方法があるかもしれませんが、とりあえず送信ができました。

mixiのドキュメントによると、mixi側が勝手にリフレッシュトークンを使えないことがあるかもしれないとのことです。OAuthコードを再度取得して処理を行う必要があるかもしれません。
完全自動化は難しいかもしれませんね。
しかし、3ヶ月ほど動かしてみたところ、とりあえず動いています。ここまで動けば大丈夫かな。

参考

mixi api 認証認可手順(新方式)
https://developer.mixi.co.jp/connect/mixi_graph_api/api_auth/

Voice API
https://developer.mixi.co.jp/connect/mixi_graph_api/mixi_io_spec_top/voice-api/

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?