本記事の対象APIは既にサポートされていません。記事は参考程度にご利用ください。
アルバムとフォトの編集
前回 はWindows Live Photo APIを利用した簡単なWebアプリケーションを作成しました。そのアプリケーションでは以下の読み取りに関する内容を実装しました。
アルバム・フォト・フォトタイプの一覧取得
フォトバイナリデータ取得
今回は、作成や編集など、以下の操作ができるようアプリケーションを拡張します。
アルバムの作成
フォトのアップロード
アルバム・フォトの名前(タイトル)変更
アルバム・フォトの削除
作成するWebアプリケーションを図1 に示します。
図1 作成するWebアプリケーション
あまり良いUIではありませんが、APIの確認には十分でしょう。前回 に作成したものに機能を追加する形で紹介します。
リクエストとレスポンス
アルバムおよびフォト情報の取得やフォトのダウンロード時には、すべてHTTP GETメソッドを使用していました。対して、アルバム作成やアップロード、名前変更、削除ではリクエスト時にPOST、PUT、DELETEといったメソッドを使います。
最初に今回のコードで共通で利用するメソッドを作成しておきます。Default.aspx.vbファイルに追記してください。アクセスするURLとHTTPメソッドを指定するとHttpWebRequestオブジェクトを返すメソッドをまず用意します。
Protected Function CreatedRequest(ByVal path As String , Optional ByVal method As String = "GET" ) As HttpWebRequest
Dim request As HttpWebRequest = DirectCast (WebRequest.Create(path), HttpWebRequest)
request.Method = method
request.Headers(HttpRequestHeader.Authorization) = String .Format("DelegatedToken dt=""{0}""" , Me .DelegateionToken)
Return request
End Function
Live委任認証用のヘッダもここで追加しています。
続いてLiveサービスからのレスポンスを取得する部分もメソッドとして作成しておきましょう。
前回 はXML文書やバイナリデータを取得して何かしらの処理をしていましたが、今回は基本的にHTTPステータスコードのみ、または それに加えてレスポンスに含まれるヘッダ内容のみを必要とします。
ここではレスポンス取得するメソッドを次のように作成しました。
Protected Function GetResponse(ByVal request As HttpWebRequest) As HttpStatusCode
Try
Using response As HttpWebResponse = DirectCast (request.GetResponse, HttpWebResponse)
Return response.StatusCode
End Using
Catch webEx As WebException
Return DirectCast (webEx.Response, HttpWebResponse).StatusCode
End Try
End Function
HttpWebRequestオブジェクトを引数として渡し、HttpStatusCodeが返ります。
アルバム作成およびフォトのアップロードに成功した場合、アップロードにより作成されたリソースのパスを示す文字列がレスポンスのLocationヘッダに格納されています。これから作成するアプリケーションではLocationで指定された値を使用していないのですが、メソッドは次のように作り呼び出しています。
Protected Function GetResponse(ByVal request As HttpWebRequest, ByRef location As String ) As HttpStatusCode
Try
location = ""
Using response As HttpWebResponse = DirectCast (request.GetResponse, HttpWebResponse)
location = response.Headers(HttpResponseHeader.Location)
Return response.StatusCode
End Using
Catch webEx As WebException
Return DirectCast (webEx.Response, HttpWebResponse).StatusCode
End Try
End Function
参照渡しによりLocationヘッダの値を返すようにしています。
アルバムの作成
最初に新しいアルバムを作成してみましょう。アルバム作成時に指定するリソースパスは、アルバムのコレクションを表すパス、つまり「/Folders」です。URL全体では次のようになります。
https://cumulus.services.live.com/@C@[LID] /AtomSpacesPhotos/Folders
そしてPOSTメソッドにより以下のXML文書を送信します。
< entry xmlns = "http://www.w3.org/2005/Atom" xmlns : LP = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns : LivePhotos = "http://dev.live.com/photos" LP : type = "Folder" >
< category scheme = "http://dev.live.com/AppStorage/scheme" term = "Folder" label = "Folder" />
< title > [アルバム名] </ title >
</ entry >
Atomプロトコルの<entry>要素になっています。<title>要素に新しく作成するアルバム名を指定しています。
以上のリクエストを行うと、作成に成功した場合、HTTPステータスコード201(Created)が返ってきます。また、作成されたアルバムのリソースパスはレスポンスに含まれるLocationヘッダによりわかります。
ここまでをアプリケーションに実装します。まず、アルバム名を指定するテキストボックスと作成ボタンをWebページに追加します。図1 では、以下のコードをDefault.aspxの<asp:Panel>タグ内に追加しています。
< fieldset >
< legend > アルバムの作成 </ legend >
< label > アルバム名: </ label >
< asp : TextBox ID = "NewAlbumNameTextBox" runat = "server" ></ asp : TextBox >
< asp : Button ID = "CreateButton" runat = "server" Text = "作成" />
</ fieldset >
作成ボタンがクリックされたときのコードは、先ほど作成したメソッドと組み合わせて、Clickイベント処理を次のように記述します。
Protected Sub CreateButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles CreateButton.Click
Dim request As HttpWebRequest = CreatedRequest("https://cumulus.services.live.com/@C@" & Me .LocationId & "/AtomSpacesPhotos/Folders" , "POST" )
Dim entry As String = _
"<entry xmlns=""http://www.w3.org/2005/Atom"" xmlns:LP=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"" xmlns:LivePhotos=""http://dev.live.com/photos"" LP:type=""Folder"">" & _
"<category scheme=""http://dev.live.com/AppStorage/scheme"" term=""Folder"" label=""Folder"" />" & _
"<title>" & HttpUtility.HtmlEncode(NewAlbumNameTextBox.Text) & "</title>" & _
"</entry>"
Dim buffer() As Byte = System.Text.Encoding.UTF8.GetBytes(entry)
request.ContentType = "application/atom+xml"
request.ContentLength = buffer.Length
Dim stream As System.IO.Stream = request.GetRequestStream
stream.Write(buffer, 0 , buffer.Length)
Dim location As String = ""
Dim status As HttpStatusCode = GetResponse(request, location)
If status = HttpStatusCode.Created Then
ListAlbums()
Else
End If
End Sub
CreateRequestメソッドを呼び出しリクエストを作成した後、<entry>要素をバイト配列としてStreamへ書き込みやContentTypeの指定を行っています。
レスポンスの取得では、成功した場合に前回 作成したメソッドを呼び出しアルバム一覧の表示を更新しています。上記コードではLocationヘッダの値をlocation変数に格納するようにしていますが、使用はしていません。作成に失敗した場合も処理を省略しています。実際には、ユーザーに失敗したこと、またその理由を通知するようにするとよいでしょう。
フォトのアップロード
フォトのアップロードは、アルバムの作成と同じPOSTメソッドを使用します。また成功した場合、Locationヘッダによりフォトのリソースパスを取得できる点で同じです。ただし、送信するデータはXML文書ではなく画像ファイルのバイナリデータとなります。
リソースパスには、フォトを追加したいアルバムのフォト一覧を示すパスを指定します。「 /Folders(n )/Photos」といったパスでしたね。アルバム自身を表すパスではなくフォトのコレクションを表すパスということに注意してください。
このほか、ContentTypeヘッダにアップロードする画像ファイルのContent Type(image/jpegなど)を指定し、フォトの名前をslugヘッダに指定します。
それでは処理を実装しましょう。Webページには、FileUploadコントロール、フォト名を指定するTextBoxとアップロードを実行するためのButtonを配置します。
< fieldset >
< legend > フォトのアップロード </ legend >
< label > フォト名: </ label >
< asp : TextBox ID = "NewPhotoNameTextBox" runat = "server" ></ asp : TextBox >
< br />
< label > ファイル: </ label >
< asp : FileUpload ID = "PhotoFileUpload" runat = "server" />
< asp : Button ID = "UploadButton" runat = "server" Text = "アップロード" />
</ fieldset >
アップロードボタンをクリックしたときの処理は次のようになります。
Protected Sub UploadButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles UploadButton.Click
Dim item As ListItem = AlbumListBox.SelectedItem
If item Is Nothing Then
Exit Sub
End If
Dim request As HttpWebRequest = CreatedRequest(item.Value, "POST" )
request.Headers.Add("slug" , HttpUtility.UrlEncode(NewPhotoNameTextBox.Text))
request.ContentType = PhotoFileUpload.PostedFile.ContentType.Replace("/pjpeg" , "/jpeg" )
Dim buffer() As Byte = PhotoFileUpload.FileBytes
request.ContentLength = buffer.Length
Dim stream As System.IO.Stream = request.GetRequestStream
stream.Write(buffer, 0 , buffer.Length)
Dim location ADim s String = ""
Dim status As HttpStatusCode = GetResponse(request, location)
If status = HttpStatusCode.Created Then
ListPhotos(item.Value)
Else
End If
End Sub
フォトを追加する先のアルバムの選択は、前回 に作成済みのアルバム一覧のリストボックスを使用しています。ContentTypeにJPEG形式のimage/pjpegを指定した場合、サポートしていない画像形式と応答されアルバムに追加できませんが、pjpeg部分をjpegとするだけで追加できますので、上記コードは置換で対応しています。
APIの制限・仕様
ここまででアルバムの作成とフォトのアップロードができるようになりました。実際に実行して確認してみましょう(図2 ) 。
図2 実行結果
実行して試す際の留意事項およびAPIの制限と思われる点をここで述べておきます。
日本語・特殊文字
アルバム名・フォト名に日本語や特殊文字を使用した場合、Bad Requestとして応答されるか、文字化けした名前となってしまうようです。Live Spacesのフォト自体は日本語に対応していますのでAPIの制限と思われます。
アルバムのアクセス制限
Live Spacesからアルバムを編集すると、インターネット上の全員・特定のユーザー・自分のみの3種類のアクセス権限を指定できます。APIにより作成した場合は、インターネット上の全員がアクセスできる状態で作成されます。
フォトタイプ
フォトにはサムネイル用やWeb用といったタイプがあり、ひとつのフォトには複数のタイプの異なるバイナリデータを持つ構造となっています。APIでアップロードした場合、大きい画像は自動で縮小され、WebReadyおよびThumbnailのタイプが作成されるようです。
アルバム・フォトの名前変更
アルバムとフォトの名前(タイトル)を変更してみましょう。名前の変更は、PUTメソッドを使用し<entry>要素から成るXML文書を送信して行います。成功した場合に応答されるHTTPステータスコードは、204(No Content)です。
指定するリソースパスと送信する<entry>要素は、アルバムとフォトで異なります。順に確認した後、コードを記述します。
アルバム名の変更
アルバム名を変更する際に指定するリソースパスは、アルバム単体を表す「/Folders(n )」といったパスになります。
<entry>要素は次のようになります。これはアルバム作成時とまったく同じです。
< entry xmlns = "http://www.w3.org/2005/Atom" xmlns : LP = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns : LivePhotos = "http://dev.live.com/photos" LP : type = "Folder" >
< category scheme = "http://dev.live.com/AppStorage/scheme" term = "Folder" label = "Folder" />
< title > [アルバム名] </ title >
</ entry >
フォト名の変更
フォト名を変更する際に指定するリソースパスは、フォト単体を表す「/Folders(n )/Photos(m )」といったパスになります。
<entry>要素は次のようになります。アルバムのときと比べて属性値が異なっています。
< entry xmlns = "http://www.w3.org/2005/Atom" xmlns : LP = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns : LivePhotos = "http://dev.live.com/photos" xmlns : Live = "LiveAtomBase:" LP : type = "Photo" >
< category scheme = "http://dev.live.com/photos/scheme" term = "Photo" label = "Photo" />
< title > [フォト名] </ title >
</ entry >
コードの記述
それでは名前変更の処理を記述しましょう。Webページには、名前入力用のテキストボックス(アルバムとフォトで共有) 、名前変更用のボタン(アルバムとフォトで個別)を配置しているものとします。また、変更する対象の選択は前回 作成済みのリストボックスから行うものとします。
< fieldset >
< legend > 選択されているアルバムまたはフォトの名前変更 </ legend >
< label > 新しい名前: </ label >
< asp : TextBox ID = "NewNameTextBox" runat = "server" ></ asp : TextBox >
< asp : Button ID = "AlbumRenameButton" runat = "server" Text = "アルバム名変更" />
< asp : Button ID = "PhotoRenameButton" runat = "server" Text = "フォト名変更" />
</ fieldset >
アルバムの名前変更の処理を記述します。Clickイベントは次のように処理します。
Protected Sub AlbumRenameButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles AlbumRenameButton.Click
Dim item As ListItem = AlbumListBox.SelectedItem
If item Is Nothing Then
Exit Sub
End If
Dim request As HttpWebRequest = CreatedRequest(item.Value.Replace("/Photos" , "" ), "PUT" )
Dim entry As String = _
"<entry xmlns=""http://www.w3.org/2005/Atom"" xmlns:LP=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"" xmlns:LivePhotos=""http://dev.live.com/photos"" LP:type=""Folder"">" & _
"<category scheme=""http://dev.live.com/AppStorage/scheme"" term=""Folder"" label=""Folder"" />" & _
"<title>" & HttpUtility.HtmlEncode(NewNameTextBox.Text) & "</title>" & _
"</entry>"
Dim buffer() As Byte = System.Text.Encoding.UTF8.GetBytes(entry)
request.ContentType = "application/atom+xml"
request.ContentLength = buffer.Length
Dim stream As System.IO.Stream = request.GetRequestStream
stream.Write(buffer, 0 , buffer.Length)
Dim status As HttpStatusCode = GetResponse(request)
If status = HttpStatusCode.NoContent Then
ListAlbums()
Else
End If
End Sub
アルバムの選択はアルバム一覧のリストボックスを利用しています。これはフォトのアップロードの処理と同じです。ただし、ListItem.Valueプロパティにはフォト一覧を示すパスが設定されていましたので、パスから「/Photos」を削除してアルバムを示すパスにしてからメソッド呼び出しをしています。
レスポンスの取得では、HTTPステータスコードしか必要ありませんので最初に作成したLocationヘッダを返さないほうのGetResponseメソッドを呼んでいます。
続いてフォト名変更のコードは次のようになります。
Protected Sub PhotoRenameButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles PhotoRenameButton.Click
Dim item As ListItem = PhotoListBox.SelectedItem
If item Is Nothing Then
Exit Sub
End If
Dim request As HttpWebRequest = CreatedRequest(item.Value.Replace("/ImageStreams" , "" ), "PUT" )
Dim entry As String = _
"<entry xmlns=""http://www.w3.org/2005/Atom"" xmlns:LP=""http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"" xmlns:LivePhotos=""http://dev.live.com/photos"" xmlns:Live=""LiveAtomBase:"" LP:type=""Photo"">" & _
"<category scheme=""http://dev.live.com/photos/scheme"" term=""Photo"" label=""Photo"" />" & _
"<title>" & HttpUtility.HtmlEncode(NewNameTextBox.Text) & "</title>" & _
"</entry>"
Dim buffer() As Byte = System.Text.Encoding.UTF8.GetBytes(entry)
request.ContentType = "application/atom+xml"
request.ContentLength = buffer.Length
Dim stream As System.IO.Stream = request.GetRequestStream
stream.Write(buffer, 0 , buffer.Length)
Dim status As HttpStatusCode = GetResponse(request)
If status = HttpStatusCode.NoContent Then
ListPhotos(AlbumListBox.SelectedItem.Value)
Else
Label1.Text = status.ToString
End If
End Sub
アルバム名変更のときとほぼ同様ですが、フォト一覧のリストボックスを利用している点、<entry>要素、レスポンス取得後にフォト一覧を更新している点で異なっています。
名前の変更は、アルバムの作成・フォトのアップロード同様に使用できる文字に制限があります。
アルバム・フォトの削除
最後はアルバムとフォトの削除についてです。削除する場合は、DELETEメソッドを使い、リソースパスには名前変更のときと同じようにアルバム単体・フォト単体を示す値を指定します。成功したときのHTTPステータスコードは204(No Content)です。
ここまでを順に実装していれば、一番単純な処理になります。さっそくコードを記述します。Webページは以下のように、アルバムとフォト用の削除ボタンを配置しているものとします。
< fieldset >
< legend > 選択されているアルバムまたはフォトの削除 </ legend >
< asp : Button ID = "AlbumDeleteButton" runat = "server" Text = "アルバムの削除" />
< asp : Button ID = "PhotoDeleteButton" runat = "server" Text = "フォトの削除" />
</ fieldset >
アルバムの削除ボタンをクリックしたときの処理は次のように記述します。
Protected Sub AlbumDeleteButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles AlbumDeleteButton.Click
Dim item As ListItem = AlbumListBox.SelectedItem
If item Is Nothing Then
Exit Sub
End If
Dim request As HttpWebRequest = CreatedRequest(item.Value.Replace("/Photos" , "" ), "DELETE" )
Dim status As HttpStatusCode = GetResponse(request)
If status = HttpStatusCode.NoContent Then
ListAlbums()
Else
End If
End Sub
送信するバイナリデータがないためコードが短いです。パスの指定部分は名前変更のときと同じListItem.Valueプロパティからコレクション用のパス部分を削除する処理をしています。
フォトの削除ボタンをクリックしたときの処理は以下のようになります。
Protected Sub PhotoDeleteButton_Click(ByVal sender As Object , ByVal e As System.EventArgs) Handles PhotoDeleteButton.Click
Dim item As ListItem = PhotoListBox.SelectedItem
If item Is Nothing Then
Exit Sub
End If
Dim request As HttpWebRequest = CreatedRequest(item.Value.Replace("/ImageStreams" , "" ), "DELETE" )
Dim status As HttpStatusCode = GetResponse(request)
If status = HttpStatusCode.NoContent Then
ListPhotos(AlbumListBox.SelectedItem.Value)
Else
End If
End Sub
以上で今回作成するWebアプリケーションは完成です。
おわりに
今回でLive Photo ATOM APIについては一区切りとして終了です。いかがでしたでしょうか。以前に本連載で紹介したPhoto APIと同じLiveユーザーデータAPIに属するLive Application Based Storage APIと比較すると、Photo APIはLive Spaces上のフォトというエンドユーザーにもわかりやすい、エンドユーザー自身も管理している、データを操作できる点で異なっていたと思います(ユーザーデータを扱うAPIですので、Application Based Storageが少し特殊だったかもしれません。) 。少し変わったAPIだと思いますので、すぐにWebサイトで利用するということは難しいかもしれませんが、こういうAPIがあることを気に留めておくと、いずれ何かのタイミングでおもしろい利用が思いつくかもしれませんね。その際に本連載が役立てば幸いです。