あらかじめ日記

雑記とかブログで使えるスクリプトとかテクニックとか。その他、音楽やアニメ、漫画の話題とかも。

【C#/XML-RPC】ブログに画像のファイル名を自動生成してアップロードするツールを作成してみた(ついでに画像のリサイズも)

上記の記事で書いているように、FC2ブログでサムネイル表示をするために「固定名_記事ID」と言うファイル名でアップしているのですが、この“記事ID”を確認するのに管理画面の記事一覧から最新記事のIDを確認して、それの+1で名前をつけて、、と言う流れでした。

まぁ、そんなに大した作業では無いのですが、面倒と言えば面倒。
ふとブログ用のツールで自動投稿とかできるので、その辺りの仕組みを使えば自動で名前設定できるのでは?(つまり最大記事数か最後の記事IDが分かれば良い)と思い、さらにどうせ自作するならついでに画像のリサイズから、アップロードまで一気にやってしまおうと考えました。

画像操作などを総合的にみて.Net Frameworkを利用するのが作りやすそうだったので勉強も含めてC#のアプリケーションで作成。

 
実際作成してみて、現在絶賛使用中のイメージがこちら。

f:id:allthewayfrom:20150510175856p:plain

大した作業ではない、、と書きましたが実際に作ってみるとやりたい事が一度にできてかなりイイです。


さて、ブログの外部からの操作はXML-RPCと言うプロトコルが大抵のブログに対応しているので、これを利用します。

XML-RPCとは、RPCプロトコルの一種であり、エンコード(符号化)にXMLを採用し、転送機構に HTTP を採用している。 - Wikipediaより


簡単に言うと、サーバーへのリクエストをXMLで書いてHTTP経由で送る、と言うもの。

※サンプルはFC2ブログ向けに書いていますが、XML-RPCに対応していればどのブログでも対応できるかと思います。ただしブログによって多少の仕様差異はあるかもしれません。

処理の流れとしては、WebRequestクラスを利用して各ブログのエントリポイントであるURLにリクエストの内容を送って結果を受け取るだけ
結果も同様にXMLで返るので、XML形式でロードしなおして結果を受け取ります。

基本パターンのサンプルはこちら。

byte[] byteData = Encoding.ASCII.GetBytes ("リクエストXML文字列");

// XML形式のデータを送信
WebRequest webReq = WebRequest.Create ("エントリポイントURL");
webReq.Method = "POST";
webReq.ContentType = "text/xml";
webReq.ContentLength = byteData.Length;

Stream reqStream = webReq.GetRequestStream ();
reqStream.Write (byteData, 0, byteData.Length);
reqStream.Close ();

// 送信のレスポンスを受け取る
WebResponse webRes = webReq.GetResponse ();
Stream resStream = webRes.GetResponseStream ();

Encoding enc = Encoding.GetEncoding ("us-ascii");
StreamReader stmRdr = new StreamReader (resStream, enc);
string readData = "";

// 受け取ったレスポンスを文字列として取得
try {
	readData = stmRdr.ReadToEnd ();
}
finally {
	resStream.Close ();
	stmRdr.Close ();
}

// XML形式の文字列をXMLとして取得
if (readData != "") {
	XmlDocument xmlDoc = new XmlDocument ();
	xmlDoc.Load (readData);
}

 これだけあれば後は簡単で、リクエストとレスポンスのフォーマットさえ分かればOKなんですね。

リクエストXML文字列は、リクエストに応じたフォーマットのXML形式の文字列を渡します。
エントリポイントURLは、各ブログサービスで用意されたリクエスト先のURL。(FC2だと「http://blog.fc2.com/xmlrpc.php」)

リクエストの基本フォーマットは上記Wikipediaのリンク先に記載の通りで、methodNameのタグにブログ情報の取得や記事やファイルのアップロードなどの実行したいAPI名書いてparamタグで渡す値を書きます。

リクエストの基本フォーマット
<?xml version="1.0"?>
<methodCall>
  <methodName>API名
  <params>
    <param>
       <value><データ型>データ</データ型>
    </param>
  </params>
</methodCall>

レスポンスの基本フォーマット
<?xml version="1.0"?>
<methodResponse>
  <params>
    <param>
        <value><データ型>データ</データ型></value>
    </param>
  </params>
</methodResponse>

※リクエスト結果は、大抵structのデータ型で返ります。

どう言うAPIがあって、どう言う仕様かは主に以下のを参考にさせて頂きながら作成していきました。

XML-RPC Support « WordPress Codex

「記事ID」の取得方法

最新記事一覧を取得する際、記事のIDが返ってくるのでそのAPIを利用します。
今回は、余分な情報は要らないのでタイトルだけ取得する簡易版のmt.getRecentPostTitlesと言うAPIを使います。

リクエスト情報は、
 ブログID、ユーザID、パスワード、取得件数

ここでブログIDが分からないので、まず先にブログ情報をblogger.getUsersBlogsと言うAPIで取得します。

リクエスト情報は、
 アプリケーションキー、ユーザID、パスワード

レスポンス結果は、
 URL、ブログ名、ブログID
(指定したキーで投稿可能なブログの一覧が取れるので、結果は配列(array)で返ります。)

アプリケーションキーは「API Keyを指定するためのもの」らしいですが、FC2ブログでは未使用(他も大抵未使用)なので空欄。
ユーザIDとパスワードは、ブログの管理画面にログインする際のものになります。

これを上記フォーマットに当てはめて、コード化するとこんな感じになります。

string reqStr = "<?xml version=\"1.0\"?>";

reqStr += "<methodCall>";
reqStr += "<methodName>blogger.getUsersBlogs</methodName>";
reqStr += "<params>";
reqStr += "<param><value><string>" + アプリケーションキー  + "</string></value></param>";
reqStr += "<param><value><string>" + ユーザID + "</string></value></param>";
reqStr += "<param><value><string>" + パスワード + "</string></value></param>";
reqStr += "</params>";
reqStr += "</methodCall>";

これを上記の「リクエストXML文字列」に渡して実行します。

結果はstructかつarrayになるので、param以下がこのようなフォーマットで返ります。

<param>
  <value><array><data>
    <value><struct>
      <member><name>url</name><value><string>http://www.hoge.jp/</string></value></member>
      <member><name>blogName</name><value><string>ブログ名</string></value></member>
      <member><name>blogid</name><value><string>1</string></value></member>
    </struct></value>
  </data></array></value>
</param>

ですので、XML形式で取得した後はこんな感じで値を取得します。


XmlNodeList structList = xmlDoc.SelectNodes("//struct");
foreach ( XmlNode structNode in structList ) {

  XmlNodeList IdList = structNode.SelectNodes( "member[name=\"blogid\"]/value/string" );
  if ( IdList != null && IdList.Count > 0 ) blogId = IdList[ 0 ].FirstChild.Value;
}


アプリケーションではユーザIDとパスの接続確認用で使われると思いますが、個人で使用するだけならブログIDは分かってしまえば固定値としてしまってもOKだと思います。

ブログIDが分かったので、ようやくgetRecentPostTitlesを実行します。取得件数は、今回ケースならは最新の1件だけで十分ですね。
※基本的に最新記事から順に返るはず、、と思います。FC2では予約投稿した記事も含めて、最初の1つ目が最新の記事として返っています。


リクエスト情報を改めて書くと、
 ブログID、ユーザID、パスワード、取得件数

フォーマットは上記のgetUsersBlogsの例を参考にparamの部分を置き換えてみてください。

レスポンス結果は、
 記事ID、ユーザID、タイトル、投稿日付

同様に指示件数分取得できるので、arrayで返ります。

このレスポンスのstruct以下はこのような感じです。

      <member><name>postid</name><value><string>1</string></value></member>
      <member><name>userid</name><value><string>default</string></value></member>
      <member><name>dateCreated</name><value><dateTime.iso8601>20150401T12:00:00</dateTime.iso8601></value></member>
      <member><name>title</name><value><string>タイトル</string></value></member>

値の取得も先ほどと同じようにセレクトするノード値を変えて取得します。

これで最新の記事IDが取得できたので+1すれば次の投稿IDになるはず、と言う前提(FC2ブログなら)でファイル名の自動設定ができました!

次でアップロードのサンプルを書いてみます。
(と、言ってもやり方はほぼ同じですが。)