Windows Media Playerのスキンを作る話

概要

Windows Media Player(以下、WMP)はスキンを何らかの手段で入手して、自分の好きな見た目に変更することができます。もちろん自分で作ることもでき、xml/javascriptを用いて比較的簡単にできるので、やっていきます。僕はn年前にiphon…1ph0n3の4sをモデルにしたものを作ったことがあり、今回はそれをip..1ph0n3の5sモデルで作りなおそうと思います。なぜ6系ではないかというと僕の携帯が5sだからです(どうでもいい)。ちなみに作ったものはできればここでダウンロードできるようにしたいのですが、現在著作権利用(林檎社公式音楽再生アプリのスクショを使用しており、著作権利用ガイドラインを読んだ感じ大丈夫ではあると思うが念のため)に関する確認の途中なので、ダウンロードファイルの設置はそこら辺が明確になり次第ということにします。では、やっていきます。

WMP Skinについて

世の中の大半のスキン内部はおおよそ以下のようなファイル構成になって(いると思)います。

  • wms(必須)
  • javascript(任意)
  • 画像素材(任意)

wmsファイルの中身はxmlで、この中で見た目を記述していきます。実際にスキンをリリースする際はこれらのファイルをまとめてzipに圧縮し、拡張子をwmzに変更すれば良いだけです。スキンを適用するときはwmzファイルをダブルクリックすると、ダウンロード・適用画面が出てくるのでポチポチやるとすぐ適用できます。
開発中はいちいちwmzにすると面倒なので、wmsファイルをダブルクリック、表示し、更新はWeb開発時のようにF5キーで行います。

まずは画像素材の支度

1ph0n3(しつこい)の画像は適当にフリーのモックアップイメージを拾ってきます(もちろん自前でも可)。今回はこちらを使わせていただくことにします。次に再生ボタンや次へボタンなどの各パーツをなんとかして調達します。今回は「前へ、次へ、再生、一時停止、プレイリスト表示、WMPライブラリへ戻る、シャッフル、リピート、シャッフル押下時、リピート押下時」を用意しました。ボタンだけでなく、シークバー、ボリュームバー用の画像なども個別に用意しないといけないので結構気合が入ります。
画像は背景を透過して描画させることができます。透過したい部分を何か単色で塗りつぶし、それを後で記述するxmlでclipping colorとして指定すれば良いので、とりあえず今回は#FFFF00(黄色)で透過したい部分を塗っておきます。

wms(xml)記述

HTMLやCSSを書いたことのある人なら、なんとなくイメージが湧きやすいと思いますが、ここはただただ書くだけです。予め意味を持たされているタグを利用しつつ、今回は以下の様な記述を行いました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<theme title="1ph0n3" copyright="@wassan128" author="wassan128" scriptfile="main.js">
<view backgroundimage="bg.png" clippingColor="#FFFF00" titlebar="false" resizable="false" onload="onload()">
<player openstatechange="meta_update()" currentitemchange="meta_update()" currentPlaylistChange="meta_update()"/>
<returnbutton top="111" left="36"
image="library.png"
cursor="hand"
/>
<button top="111" left="235"
image="list.png"
onclick="Jscript:list.visible=!list.visible"
uptooltip="playlist"
cursor="hand"
/>
<text top="117" left="132" id="pl_numer"
foregroundcolor="#666666"
fontStyle="bold"
fontFace="メイリオ"
fontSize="5"
value="000"
/>
<text top="117" left="160" id="pl_denom"
foregroundcolor="#666666"
fontStyle="bold"
fontFace="メイリオ"
fontSize="5"
value="000"
/>
<playbutton top="435" left="120"
image="play.png"
cursor="hand"
/>
<pausebutton top="435" left="120"
image="pause.png"
cursor="hand"
onClick="player.controls.pause();"
visible="wmpenabled:player.controls.pause"
/>
<prevbutton top="435" left="58"
image="prev.png"
cursor="hand"
/>
<nextbutton top="435" left="183"
image="next.png"
cursor="hand"
/>
<repeatbutton top="482" left="38"
image="repeat.png"
downimage="repeated.png"
cursor="hand"
/>
<shufflebutton top="482" left="200"
image="shuffle.png"
downimage="shuffled.png"
cursor="hand"
/>
<minimizebutton top="518" left="120"
image="minimize.png"
cursor="hand"
/>
<closebutton top="0" left="192"
image="close.png"
cursor="hand"
transparencycolor="#FFFF00"
/>
<tracknametext top="393" left="40" id="trackname"
width="220"
fontsize="7"
foregroundcolor="black"
backgroundcolor="transparent"
scrolling="false"
scrollingamount="3"
justification="center"
/>
<text top="415" left="40" id="author_text"
width="220"
fontsize="5"
foregroundColor="darkslategray"
fontStyle="regular"
tabStop="false"
justification="center"
value="jscript:player.currentMedia.getItemInfo('Author');"
/>
<volumeslider top="465" left="70"
transparencycolor="#FFFF00"
foregroundimage="vol_fore.png"
backgroundimage="vol_back.png"
thumbimage="vol_ball.png"
bordersize="7"
direction="horizontal"
/>
<slider top="378" left="79"
width="140"
bordersize="1"
transparencycolor="#FFFF00"
slide="false"
foregroundimage="seek_fore.png"
backgroundimage="seek_back.png"
thumbimage="seek_ball.png"
direction="horizontal"
min="0"
max="wmpprop:player.currentmedia.duration"
ondragend="player.controls.currentposition=value;"
value="wmpprop:player.controls.currentposition"
tooltip="seek"
/>
<text top="379" left="40"
width="30"
fontFace="メイリオ"
fontsize="5"
foregroundcolor="dimgray"
value="wmpprop:player.controls.currentPositionString"
/>
<text top="379" left="230"
width="30"
fontSize="5"
fontFace="メイリオ"
foregroundcolor="dimgray"
value="wmpprop:player.currentMedia.durationString"
/>
<subview id="list" visible="false" top="140" left="35" backgroundcolor="none" onload="meta_update()">
<playlist top="0" left="0"
width="232"
height="232"
itemPlayingColor="whitesmoke"
itemPlayingBackgroundColor="gray"
disableditemcolor="#808080"
foregroundcolor="darkslategray"
backgroundcolor="whitesmoke"
dropdownvisible="false"
columnsvisible="false"
/>
</subview>
<subview id="album_art_work" visible="true" top="140" left="35" backgroundImage="WMPImage_AlbumArtLarge" width="232" height="232" resizeBackgroundImage="true" passThrough="true" justification="center"></subview>
</view>
</theme>

<theme>:

テーマ全般に関するタグです。スキンのタイトル(スキンセレクターで表示される名前)、著作者表示、製作者に加えてJavaScriptのファイルを指定します。複数ある場合は;(セミコロン)で区切るようです。

<view>:

htmlでいうbodyタグといったところでしょうか。背景画像やその他表示に関する属性を記述できます。clipping colorで指定した色が透過されて描画されます。

<subview>:

htmlでいうdiv(ここでhtml5信者に刺される)的なタグということにしておきましょう。

<player>:

プレイヤーのイベントハンドラをここで登録しました。各イベントの発生毎にmeta_upload関数が呼び出され、メタ情報が更新・再描画されます。

<returnbutton>:

WMPのライブラリ(何を言っているかわからないかもしれないが、恐らくほとんどの人が一度は見たことがあるはず)を表示するボタンを指定しています。

<button>:

ボタンです。今回はプレイリストを表示するようにonclickで意味付けをしたものが書いてあります。

<text>:

テキストです。idを指定して、javascriptで書き換えているものがいくつかあります。

<playbutton>:

三角の再生開始ボタンです。

<pausebutton>:

一時停止ボタンです。

<prevbutton>:

曲を早戻ししそうな見た目をしていますが、プレイリストのひとつ前の曲へ移動するボタンです。

<next>:

prevbuttonの逆をするボタンです。

<repeat>:

プレイリスト内の曲をリピート再生するか指定するボタンです。

<shuffle>:

プレイリスト内の曲を順番通りでなくランダムに再生するか指定するボタンです。

<minimizebutton>:

スキン表示を最小化でタスクバーに隠すボタンです。

<closebutton>:

閉じるボタンです。

<tracknametext>:

再生中の曲名を表示します。

<volumeslider>:

実際に動かす球(?)とボリューム出てます色バーと出てません色バーを画像で指定すると良い感じにボリュームバーが出来上がります。

<slider>:

ボリュームバーのように3つ画像を用意・指定するとシークバーが描画されます。

<playlist>:

プレイリストに入っている曲を描画する領域です。

その他のタグや各タグに指定できる属性はスキンプログラミングリファレンスで確認できます。凝りたい方はこちらを一読されると良いと思います。

JavaScriptの記述

JavaScriptでは再生中の曲が変わった時などに、メタ情報(アルバムアートワーク、作曲者、曲名…)の更新を行います。今回のコードは以下の様な感じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* When start up skin */
function onload() {
meta_update();
}
/* Control about meta data(playlist, track) */
function meta_update() {
// related playlist
pl_denom.value = player.currentPlaylist.count;
pl_numer.value = getIdx();
// update album art work
album_art_work.backgroundImage = "WMPImage_AlbumArtlarge";
// update track author name text
author_text.value = player.currentMedia.getItemInfo("author");
if (author_text.value == "") {
author_text.value = "undefined";
}
}
/* Current media index */
function getIdx() {
var pl = player.currentPlaylist;
for (var i = 0; i < pl.count; i++) {
if (pl.item(i).name == trackname.value) {
break;
}
}
return i + 1;
}

meta_update関数はメタ情報を更新して、上のwmsファイルで指定したidの要素を書き換える処理をしています。getIdx関数はプレイリストの何番目の曲を再生しているのかというのを表示するために、今何番目が流れているのかを調べる関数です(リファレンスをぱっと見た感じそういうメンバをcurrentPlaylistオブジェクトに見つけられなかったので適当に書いたけど、本当にないのかよくわからず…)。これをwms内でイベントハンドラに登録する形で記述してあるのがわかると思います。重要なのは<player>に登録してある、currentItemChangeイベント等でしょう。これは曲が変わるときなどに発生するイベント(説明が雑)なので、ここでメタ情報を更新しておけば、良い感じなります。

できたもの

おわりに

昔作った時も思いましたが、結構情報が少ない印象です(リファレンス見ればだいたい解決しますが)。n年前に制作した時はどうやって情報を集めたかあんまり覚えていませんが、個人的には実際にあるスキンを解凍してソースを見てみるというのが一番手っ取り早いと思います(もちろん、作者がそれを許諾しているスキンで)。あとはcss書いたことがあるとfontSizeなどの属性が雰囲気でわかるので、書きやすいと思います。JavaScript部分もあんまり最初リファレンス読まずに書いていたので手探り状態で、CurrentItemChangeにたどり着くまで結構かかりました。
冒頭でも書いた当スキンの公開についてですが、こちらの著作権利用に関するガイドラインを見た限りは問題ないような気がするのですが、はっきりわからないので現在問い合わせメールの返答待ちをしています。はっきりし次第公開できれば良いなと思っています。ソースの方は問題ないと思うので、スキン作りの参考になれば幸いです。

参考資料