2015年7月20日月曜日

[MovableType] [Data API] [Perl] 画像タイプのカスタムフィールドを持つエントリーをData APIを使って投稿する


MovableTypeで画像タイプのカスタムフィールドを持つエントリー(記事)をData APIを使って投稿する方法について(しかもPerlで)

これを実現するには、
1.画像をData APIを使ってアップロードし、アイテム(Asset)に登録する
2.エントリーをData APIを使って投稿する際に、1で登録したアイテムを紐付けて登録する
という手順が必要です。

サンプルを見るのが一番わかりやすいと思いますので、次にコードを提示します。

#!/usr/bin/perl -w
use strict;
use warnings;
use LWP::UserAgent;
use HTTP::Request::Common;
use JSON;
use URI::Escape;
use Data::Dumper;
use Encode;
my $api_url = 'http://localhost/cgi-bin/mt/mt-data-api.cgi';
my $blog_id = 1;
my $res;
my $json;
my $token;
my $lwp = LWP::UserAgent->new;
$lwp->timeout(20);
# authentication
$res = $lwp->post(
"$api_url/v1/authentication",{
username => '[MTのログインアカウント名を指定]',
password => '[指定したアカウントのパスワードを指定]',
clientId => 'test', # 任意の文字列を指定する
}
);
$json = from_json($res->content);
$token = $json->{accessToken};
if(! $token){
print 'error authentication';
return;
}
# 画像を投稿(アップロード)する
my $img_ep = "$api_url/v2/sites/$blog_id/assets/upload"; # 画像(厳密にはAsset)をアップロードするエントリーポイント
my $request = POST($img_ep, Content_Type => 'form-data', 'X-MT-Authorization' => "MTAuth accessToken=$token", Content =>
{
path => '',
file => ['/Users/takahiro/Desktop/IMG_1498.jpg'], # サンプルとしてデスクトップに置いたIMG_1498.jpgという画像を投稿(アップロード)する
autoRenameIfExists => 'true',
}
);
$res = $lwp->request($request);
$json = from_json($res->content);
# check status
if (! &check_status($json)) { exit; }
# 記事を投稿する(画像タイプのカスタムフィールドを持ち、そのカスタムフィールドには先に投稿した画像を紐付ける)
my $ep = "$api_url/v2/sites/$blog_id/entries"; # 記事を投稿するエントリーポイント
$request = POST($ep, 'X-MT-Authorization' => "MTAuth accessToken=$token");
my $params = {
entry => encode_json({
title => 'title - test(asset: ' . $json->{id} . ')',
status => 'Publish',
customFields => [
{
basename => 'custimg',
value => sprintf(qq{<form mt:asset-id='%d' class='mt-enclosure mt-enclosure-%s' style='display: inline'><a href="%s"><img src="%s"/ width="500"></a></form>}, $json->{id}, $json->{class}, $json->{url}, $json->{url}),
},
],
})
};
$request->content(join('&', map{$_.'='.$params->{$_}} keys %$params));
$res = $lwp->request($request);
$json = from_json($res->content);
# check_status
if (! &check_status($json)) { exit; }
# Data APIからのレスポンスをチェックして、不正であれば詳細メッセージ等を表示する
sub check_status {
my $json = shift;
if(! $json->{id}){
my $message = $json->{ error }->{ message };
$message =~ s/\\x{([0-9a-z]+)}/chr(hex($1))/ge;
print $json->{error}->{code};
print ':';
print $message;
return 0;
}
return 1;
}
view raw gistfile1.pl hosted with ❤ by GitHub
(私的)ハマりポイントは次の通り。

1.画像をアップロードする場合にはX-MT-Authorizationでトークンを渡すだけでなく、Content-Type: multiple/form-dataも渡す必要がある。boundaryとか自力でやろうとするとこれは大変なので、HTTP::Request::CommonのPOSTメソッドを使いました。POSTメソッドにて、POST(url, Content_Type => 'form-data', ... );とすることでHTTP::Request::Commonがboundaryも含めたヘッダをよしなに処理してくれます。POSTメソッドへの引数がContent-Typeではなく、Content_Typeになっていることに要注意です。

2. 画像の実体の指定もHTTP::Request::CommonのPOSTメソッドを利用すれば、Contentパラメータ内で['ファイルのパス']とすることで処理してくれます。自力でファイルを開いたり(binmode指定して頑張ったりもして)、IO::Fileオブジェクト作って渡してみたり、色々やってみましたが、これらの方法はうまくいきません。

3.画像タイプのアセットを記事に紐付けて、編集画面にも埋め込んで表示するには、サンプルの通り、
 sprintf(qq{<form mt:asset-id='%d' class='mt-enclosure mt-enclosure-%s' style='display: inline'><a href="%s"><img src="%s"/ width="500"></a></form>}, $json->{id}, $json->{class}, $json->{url}, $json->{url})
というように、formタグの中にimgやaタグを組み込んだ値を指定します。style='display: inline;'というように';'を含んだ値を渡すとJSONモジュールがエラー吐いて死にますので、外します。formの他の属性はおまじないだと思ってください。

参考:
 MovableType Data API v2
 HTTP::Request::Common
 実装メモ:Movable Type 6の便利なData APIを利用して画像を出力する : アークウェブのブログ
 

0 件のコメント:

コメントを投稿