aTunesで連続再生できるようになりました

aTunesがようやく使い物になるplayerになりました。

http://x-jukebox.com/atunes
具体的には連続再生に対応しました。playerにYouTubeのflashを貼り付けていただけなので1動画の再生が終わるとそのまま放置。1曲再生で終わるplayerでは作業用なんかには使えないわけで・・・でもeventとれないから仕方ないじゃん。。。と思っていました。

javascriptでハンドリングできないか調べようとしたらあっさり見つかりました。

http://code.google.com/intl/ja/apis/youtube/js_api_reference.html#Events
別にhackとかなんでもなく普通にJavascript APIが公開されていました。これを使ってplayerの再生が終了したら次の動画のplayerをajaxでとってきてreplaceするというコードを書きました。内部でリスト管理するようにしたのでバグとかがあるかもしれません。

連続再生できると今度は音楽ビデオじゃないものはスキップする機能が欲しくなりました。自前のdbにMusicVideoのフラグを用意しようかと思ったりしています。

YouTube Data APIで取得したデータをWPFのリストで表示する その2

宣言通り、ItemsControlとListViewについて。

前回、ListBoxを使って動的に項目を並べることをやりましたが、ListBoxはあくまでListBoxなわけで並んだ項目はListBoxItemの中にあり、ListBoxItemが選択できます。別に選択する必要もなく、ただ単に画像を並べたいということもあると思います。そのやり方に少し悩みました。StackPanelのChildrenにコードで追加すればできるのですが、ListBoxに配列をBindしたようにスマートにやりたいものです。

ItemsControlでそれができると知りました。ListBoxやListViewの継承関係は下記のようになっています。

System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.FrameworkElement
System.Windows.Controls.Control
System.Windows.Controls.ItemsControl
System.Windows.Controls.Primitives.Selector
System.Windows.Controls.ListBox
System.Windows.Controls.ListView

ItemsControlには項目の配列を並べることが選択機能なしにできるので単に項目を並べるときに使えました。ListBoxのXAMLを書いたときに値を変更したItemsSource、ItemTemplate, ItemsControl.ItemTemplateなどはまさにItemsControlのものなのでListBoxのXAMLをそのまま流用できます。(その逆もしかり)

<ItemsControl Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" ItemHeight="100" ItemWidth="100"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

またListViewでも同じようにXAMLが書けます。ListViewのReport形式の表示をGridViewつかって表示してみます。

<ListView Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ListView.View>
<GridView ScrollViewer.VerticalScrollBarVisibility="Visible">
<GridViewColumn Header="Thumbnail">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Thumbnail}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Title}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Author">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Author}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>

こんな感じで、GridViewでもカラムの中でどういうコントロールで表示するかをGridViewColumn.CellTemplateを使って表現できます。

同じCollectoinデータをListBox, ItemsControl, ListViewに設定して並べて表示してみました。

WPFYouTube200805240.jpg

最終的なXAMLは以下の通りです。

このサンプルプログラム(VS2008)は
WPFYouTube.zipからダウンロードできます
<Window x:Class="WPFYouTube.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:me="clr-namespace:WPFYouTube"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<CollectionViewSource Source="{DynamicResource VideoItems}" x:Key="VideoItemCollection"/>
<DataTemplate x:Key="VideoOnItemsControl">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Title}"/>
<Image Source="{Binding Path=Thumbnail}"/>
<TextBlock Text="{Binding Path=Author}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" Grid.Column="0" x:Name="tbxKeyword" Text="ドラゴンボール"/>
<Button Grid.Row="0" Grid.Column="1" Content="Search" Click="Button_Click"/>
<ListBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
<ItemsControl Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" ItemHeight="100" ItemWidth="100"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ListView Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ListView.View>
<GridView ScrollViewer.VerticalScrollBarVisibility="Visible">
<GridViewColumn Header="Thumbnail">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding Path=Thumbnail}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Title}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Author">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Author}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>

YouTube Data APIで取得したデータをWPFのリストで表示する

ようやくWPFもわかってきたのですが、なかなか情報が少ない状況です。.NET 3.0がリリースしてしばらく経ったと思うのですがあまり流行っていないような気もします。さんざん苦労したので調べてわかったことなどを書いてみようと思いました。

別にWPFに限ったことではないのですが、新しいプラットフォームでアプリをつくるときに必ずといって悩むことがあります。

特にUI系のサンプルプログラムはUIコントロールの説明を重視するために静的なデータを表示することがほとんどです。コードの中に表示する文字列や画像のパスが入っていることも珍しくありません。

ところが実際にアプリを作るときは、実行時には表示するデータはまだわからず、何からのアクションに伴いデータを取得して表示するということがよくあります。しかし、表示する項目が動的に変わるようなサンプルはまだ少ないように思います。

WPFを使ったときに複数のアイテムを表示する方法にかなり悩んだので、今回は、YouTube Data APIで検索した結果をいくつかのコントロールで表示するサンプルプログラムを書いてみることにします。

1. データのカプセル化(モデルの作成)

何かしらのデータを表示する際に単にその名前だけを表示することは少なく、複数のメタデータを並べて表示することが多いと思います。たとえばRSS Readerの記事の項目で言えば、タイトルだけじゃなく、作者や、公開日時も表示しますし、YouTubeなどの動画系の項目なら名前だけじゃなく、サムネイルやタグなんかを表示すると思います。

ますはこういったデータの固まりをモデルとしてクラスを用意します。今回はGoogle Data API SDKを使うので、Google.GData.Client.AtomEntryをモデルとして使います。(名前のとおりAtomEntryは基本的なモデルクラスでYouTube用のVideoデータのプロパティ、たとえば動画のサムネイルなどはとれないようです)

2. UI用Adapterクラスの作成

モデルとUI用のクラスを別に分ける必要がないのですが、クラスの再利用を考えるとデータの管理する箇所がUIのフレームワークに依存するのを避けるために別ける方が良いと思います。(そもそも今回はモデル用のGoogle.GData.Client.AtomEntryは変更できないのだが)

具体的にはSystem.ComponentModelにあるINotifyPropertyChangedを継承したUI用のクラスを作ります。名前の通りプロパティの変更をUIコントロールに通知することができ、あとはXAMLでプロパティをBindするだけになるので非常に楽ちんです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using Google.GData.Client;
using Google.GData.Extensions;
namespace WPFYouTube
{
  public class UIVideoItem : INotifyPropertyChanged
  {
    public UIVideoItem(AtomEntry entry)
    {
      Title = entry.Title.Text;
    }
    public string Title { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string info)
    {
      if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
  }
}

ますは名前だけ返すクラスにしておきます。

3. Collectionの用意

リストにはUI用のクラスの配列を渡します。ここのやり方を知るのに時間がかかりました。配列の内容の変更を通知してくれるObservableCollectionを使ってXAMLでBindをします。

ちなみにこれから説明する例が素直なやり方なのかはよくわかっていません。

Windowのクラス側にてObservableCollectionのテンプレートを使いUIVideoItemの配列を定義します。

private ObservableCollection<UIVideoItem> videoItems = new ObservableCollection<UIVideoItem>();

XAMLの方でCollectionViewSourceを定義して、SourceにWindowの”VideoItems”というリソースを動的リソースとして指定します。(ObservableCollection<UIVideoItem>のXAMLでの書き方がわからなかったのでこうしてます)

<Window.Resources>
<CollectionViewSource Source="{DynamicResource VideoItems}" x:Key="VideoItemCollection"/>
</Window.Resources>

動的リソースの”VideoItems”は、Windowクラスのプロパティではありません。従ってpublicのメンバでVideoItemsを定義しても意味がありません。Resourcesメンバに指定する必要があります。

public Window1()
{
  this.Resources["VideoItems"] = this.videoItems;
  InitializeComponent();
}

上記によって、動的リソースの”VideoItems”にObservableCollection<UIVideoItem>を指定します。

最後にXAMLの方に戻って、CollectionViewSourceをListBoxのItemsSourceにBindします。これでC#側でmediaItemsを変更するだけでリストの内容が変えることができます。

<ListBox ItemsSource="{Binding Source={StaticResource VideoItemCollection}}"/>

実行してみましょう。(XPクラシックモードです)
WPFYouTube200805230.jpg

なんじゃこれは?ですが、正しい挙動です。ListBoxは項目のToStringの結果を表示するのでこうなります。

4. ItemTemplateの用意

UIVideoItemに下記のようなToStringを実装すればリストボックスにタイトルが並ぶようになります。

public override string ToString()
{
  return Title;
}

しかし、これだけならCollectionViewSource にstringの配列を渡すだけでもできてしまうので、モデルやUIクラスを作った意味があまりありません。そこでリストの項目に複数のプロパティをそれぞれ別のコントロールを使って表示するようにします。とりあえずAuthorプロパティをUIVideoItemに用意します。

public UIVideoItem(AtomEntry entry)
{
  Title = entry.Title.Text;
  Author = (entry.Authors != null && entry.Authors.Count > 0) ? entry.Authors[0].Name : "";
}
public string Title { get; set; }
public string Author { get; set; }

ListBoxはデフォルトでは項目のToStringを単にテキストラベルで表示するだけですが、表示方法をItemTemplateで指定できます。

<ListBox ItemsSource="{Binding Source={StaticResource VideoItemCollection}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Title}"/>
<TextBlock Text="{Binding Path=Author}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>

これを実行すると、TitleとAuthorがStackPanelで水平に並べられて表示されます。

WPFYouTube200805231.jpg

水平に並べたためあまり効果は見えませんが、TItleとAutorが別々のTextBlockになっているのでTitleだけ太字にしたり、Authorだけ色を変えるなどスタイルの変更が柔軟に対応できます。

なお項目の表示方法を共通化したい場合などは、リソースとしてあらかじめ宣言しておくことができます。

<Window.Resources>
<CollectionViewSource Source="{DynamicResource VideoItems}" x:Key="VideoItemCollection"/>
<DataTemplate x:Key="VideoOnItemsControl">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Title}"/>
<TextBlock Text="{Binding Path=Author}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>

上記のように用意しておくと、ListBoxのところは

<ListBox ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}"/>

で済むようになります。

5. コンテナのTemplateの変更
表示方法を変更できるのは項目だけではありません。項目を入れている箱、コンテナも変更することができます。通常リストボックスは垂直方向に項目が並びますがこれを水平方向に変えることがWPFでは簡単にできます。

<ListBox ItemsSource="{Binding Source={StaticResource VideoItemCollection}}" ItemTemplate="{StaticResource VideoOnItemsControl}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>

と書くと、、、

WPFYouTube200805232.jpg

のようになります。

だいぶ長くなってしまいました。今日はここまでにします。次回はItemsControlとListViewについて書いてみたいと思います。

YouTubeと一連託生なWebサイトをつくってしまった

YouTubeがダウン–原因はパキスタンでのアクセス遮断か
http://japan.cnet.com/news/media/story/0,2000056023,20368032,00.htm
YouTubeが落ちていたらしい。CNETの記事によると太平洋時間午前11時30分頃に発生し、午後12時15分に復旧とのこと。

時差が17時間くらいだったと思うので日本時間にすると朝の4:30-5:15くらい?確かにその時間にaTunesがアクセスできなくて、ログをみるとYouTubeへの接続が全部タイムアウトしていたので、YouTubeの機嫌を損ねる何かをしてしまったのか??と焦りました。

週初めのそんな時間に普通に起きてコード書いていた自分は社会人失格ですが、YouTubeに接続できないと、ページが開けないというWebサイトを作ってしまったのはエンジニア失格かも。

つながらないなら、つながらないなりにエラー表示しないと。。。

アーティスト単位で音楽を楽しむaTunesをリリースします

x-jukebox.com. aTunes .
http://x-jukebox.com/atunes
ソニーを辞めベンチャーに転職して早一年。そろそろmakoto_kwのソロプロジェクトを開始します。本気出すよ!(←最初から出してください。orz)
x-jukebox.comでは音楽を楽しむためのWebサービス・Webアプリをリリースしていくつもりです。今回その第一弾としてアーティスト単位でYouTubeから動画を検索して楽しむことができるaTunesをリリースします。その昔リンクからいろんなサイトを巡るネットサーフィンという言葉が生まれましたが、これはそれをアーティスト単位で行うものです。

aTunes.jpg
ソニーのアーティストリンクに似ていますが、関連アーティストはAudioScrobllerのWebサービスを利用しています。AudioScrobller x YouTubeという誰もが考えそうなマッシュアップですでに同じようなサービスもありそうな気がすごくするのですが、、、そんなの関係ねぇ。ってことで知らないふりをして作りました。

次の機能拡張では好きなアーティストの新曲を忘れずにチェックしたいことでAmazonとの連携というこれまたありふれたマッシュアップを実現するつもりです。

サーバがしょぼすぎるのであまりいじめないでください。。。

P.S.
最初のアーティストがJanne Da Arcなのはmakoto_kwがJanne Da Arcerだからであります。