高度なスクリプトサイドバープラグインの作成

はじめに


このドキュメントはVBScript、XSLスタイルシートおよびHTMLDocument(DHTML)の知識があることを前提に記述しています。

また、OPML形式XMLの知識があることを推奨します。

この解説について

LunaItemXmlBuilderLunaScriptSidebar以外のオブジェクトも使って、YouTubeの検索結果をサイドバーに表示するプラグインを作成します。

使用するオブジェクトとメソッド


例として、Lunascapeで現在検索ボックスに入力されている語句からYouTubeの検索結果を取得してサイドバーに表示するサンプルを作成します。

このサンプルで用いるオブジェクトとメソッドは以下のとおりです。

オブジェクト 利用するメソッド
Lunascape SearchBarString
LunaScriptSidebar BeginThread

ConnectEvent

SetData

GetData

SetXml

Update

LunaItemXmlBuilder GetRootItemID

AppendChild

ItemTitle

ItemURL

ConvertToSearchString

ToString

LunaHtmlUtility LoadHTML

解析スクリプト


sample.vbsを次のように変更します。

XSLスタイルシートも変更した後にLunascapeを再起動し、サイドバー内の検索ボックスに語句を入力して検索ボタンをクリックすると、YouTubeの検索結果がサイドバーに表示されます。

またLunascapeの検索バーから検索を行うことでも、検索バーの語句を用いたYouTubeの検索結果がサイドバーに表示されます。

'Lunascape Co., LTD. All rights reserved.

‘ 検索バーに入力された語句を保持しておくための変数
Dim g_lastSearchWord

‘ Function main

‘ フレームワークから呼び出されるエントリポイントです。
‘ Lunascapeで現在検索ボックスに入力されている語句が
‘ 更新した際にその語句でYouTubeを検索します。
Function main()
main = True

‘ 検索バーに入力されている語句を保持しておく
g_lastSearchWord = Lunascape.SearchBarString

‘ Lunascapeでドキュメントの読み込みが完了した際のイベントに
‘ documentcomplete関数を接続する
LunaScriptSidebar.ConnectEvent _
“DocumentComplete”, _
“documentcomplete”
LunaScriptSidebar.Update()
End Function

‘ Function documentcomplete

‘ Lunascapeでドキュメントの読み込みが完了した際のイベントに
‘ 接続される関数です。
Function documentcomplete(disp, url)
documentcomplete = False

‘ 直前に検索バーに入力されていた語句
Dim searchWord
searchWord = g_lastSearchWord

‘ 検索バーに入力されていた語句を更新
g_lastSearchWord = Lunascape.SearchBarString

‘ 検索バーに入力されていた語句が更新されたら
‘ バックグラウンドスレッドでYouTubeの検索結果
‘ を解析します。
If searchWord <> g_lastSearchWord Then
LunaScriptSidebar.SetData _
“SearchWord”, _
Lunascape.SearchBarString
LunaScriptSidebar.BeginThread _
“sample.vbs”, _
“parse_youtube_result”, _
“”
End If
End Function

‘ Function get_video_id

‘ ビデオへのリンクからアイテムのIDを取得する関数です
Function get_video_id(strHref)
Dim s
s = Split(strHref, “=”, -1, 1)
get_video_id = s(1)
End Function

‘ Function is_thumbnail

‘ ビデオへのリンクが<a><img></a>形式かを判定する関数です
Function is_thumbnail(a)
Dim children
Set children = a.children
Dim e
For Each e In children
If LCase(e.tagName) = “img” Then
is_thumbnail = True
Else
is_thumbnail = False
End If
Exit For
Next
End Function

‘ Function parse_youtube_result

‘ URLで指定されたYouTubeの検索結果ページから
‘ ビデオへのリンクを抽出してアイテムを追加する
‘ 関数です
Function parse_youtube_result()
parse_youtube_result = True

Dim strSearchWord
strSearchWord = LunaScriptSidebar.GetData(“SearchWord”)

‘ URLを組み立てる
Dim strURL
strURL = “http://www.youtube.com/results?search_query=&#8221; & _
LunaItemXmlBuilder.ConvertToSearchString( _
strSearchWord, “utf-8”)

‘ ルートアイテムのIDを取得
Dim idRoot
idRoot = LunaItemXmlBuilder.GetRootItemID()

‘ 検索結果ページをダウンロード
Dim document
Set document = LunaHtmlUtility.LoadHtml(strURL)

Dim oMainContent
Set oMainContent = document.getElementById(“results-main-content”)

‘ リンクを列挙
Dim links
Set links = document.links

Dim lastHref
lastHref = “”
Dim a
For Each a In links
‘ ビデオへのリンクであればアイテムを追加する
If oMainContent.contains(a) And _
InStr(a.href, “watch?v=”) And _
is_thumbnail(a) = False And _
a.title <> “” And _
a.href <> lastHref Then
lastHref = a.href
‘ ビデオアイテムのIDを取得
Dim strId
strId = get_video_id(a.href)

‘ アイテムを追加
Dim itemVideo
itemVideo = LunaItemXmlBuilder.AppendChild( _
idRoot, “FAVORITE_LINK”, “”)
‘ タイトルは<a>タグの内部テキストを用いる
LunaItemXmlBuilder.ItemTitle(itemVideo) = a.innerText
‘ URLはIDのみを登録する
‘ 実際のURLの解決はXSLスタイルシート側で処理する
LunaItemXmlBuilder.ItemURL(itemVideo) = strId
End If
Next

LunaScriptSidebar.SetXml(LunaItemXmlBuilder.ToString())
LunaScriptSidebar.Update()
End Function

Lunascapeで検索を行うと、その検索語句によるYouTubeの検索結果がサイドバーに表示されます。

サイドバーに表示されているアイテムをクリックするとLunascapeでビデオクリップが表示されます。

スクリプトの解説


Dim g_lastSearchWord

この変数は検索バーに入力された語句を保持しておくためのグローバル変数です。

g_lastSearchWord = Lunascape.SearchBarString

Lunascapeの検索バーに入力されている語句を変数に代入しています。

LunaScriptSidebar.ConnectEvent "DocumentComplete", "documentcomplete"

LunaScriptSidebarオブジェクトを通じて、Lunascapeで発生したイベントとスクリプトの関数を関連付けている処理です。

Lunascapeで表示されているアクティブなページの読み込みが完了した際にdocumentcomplete関数がフレームワークから呼び出されます。

Function documentcomplete(disp, url)



End Function

この関数はLunascapeで現在アクティブなタブでドキュメントの読み込みが完了した際に呼び出されます。

詳細はConnectEventで接続可能なイベントを参照してください。

documentcomplete = False

実際の解析作業は後述する非同期処理で行うため、この関数はFalseを返します。

Falseを返すことでフレームワークはこの時点ではコンテントの内容を更新しません。

' 直前に検索バーに入力されていた語句
Dim searchWord
searchWord = g_lastSearchWord
‘ 検索バーに入力されていた語句を更新
g_lastSearchWord = Lunascape.SearchBarString

‘ 検索バーに入力されていた語句が更新されたら
‘ バックグラウンドスレッドでYouTubeの検索結果
‘ を解析します。
If searchWord <> g_lastSearchWord Then
LunaScriptSidebar.SetData “SearchWord”, Lunascape.SearchBarString
LunaScriptSidebar.BeginThread _
“sample.vbs”, “parse_youtube_result”, “”
End If

Lunascapeの検索バーから検索された語句を取得して、直前の語句と異なっていれば解析処理を実行します。

解析処理はparse_youtube_result関数を直接呼び出すのではなく、BeginThreadメソッドを用いてバックグラウンド処理として行っています。バックグラウンドで処理することにより、Lunascapeが応答しなくなることを避けています。

またバックグラウンド処理ではLunascapeオブジェクトは利用できないため、LunaScriptSidebarオブジェクトのGetDataメソッドを利用して取り出しています。

Function parse_youtube_result()



End Function

この関数はYouTubeから検索結果をダウンロードして解析し、ビデオクリップの情報をアイテムを追加する関数です。

Dim strSearchWord
strSearchWord = LunaScriptSidebar.GetData("SearchWord")

LunaScriptSidebarオブジェクトのSetDataメソッドを利用して格納していた検索語句を取り出しています。

strURL = "http://www.youtube.com/results?search_query="_
& LunaItemXmlBuilder.ConvertToSearchString(strSearchWord,_
"utf-8")

検索結果をダウンロードするためのURLを組み立てています。

strSearchWord変数に代入されている検索語句はそのままではURLとして利用できません。

LunaItemXmlBuilderオブジェクトのConvertToSearchStringメソッドを用いてURLとして利用できる形式に変換しています。

なお、変換形式はYouTubeサイトの仕様にあわせて”utf-8″です。

Dim document
Set document = LunaHtmlUtility.LoadHtml(strURL)

LunaHtmlUtilityオブジェクトのLoadHTMLメソッドで検索結果ページをダウンロードしています。LoadHTMLメソッドでダウンロードしたHTMLはDocument Object Model(DOM)オブジェクトに変換されるので、解析処理はDOMにアクセスして行うことになります。

Dim links
Set links = document.links
Dim lastHref
lastHref = “”
Dim a
For Each a In links

リンクアイテムを解析することでビデオクリップへのリンクを見つけるためにリンクの一覧を取得し、個々のリンクを列挙しています。また、重複するリンクをチェックするための変数を初期化しています。

前述したようにダウンロードしたHTMLページはDOMオブジェクトなので、リンク一覧の取得にはlinksメソッドを利用し、列挙にはVBScriptのFor…Each文を利用しています。

If oMainContent.contains(a) And InStr(a.href, "watch?v=")_
is_thumbnail(a) = False And _
a.title <> "" And _
a.href <> lastHref Then



End If

リンクアイテムがビデオクリップへのリンクかを判定しています。タイトルがないもの、重複するリンクはスキップします。

ビデオクリップへのリンク先が http://www.youtube.com/watch?v=ビデオクリップのID という形式になっていることを利用して判定をしています。

またビデオクリップへのリンクはテキストからのリンクとサムネイルからのリンクがあるため、サムネイルからのリンクはスキップしています。

LunaItemXmlBuilderオブジェクトへのアイテムの追加は簡単なスクリプトサイドバープラグインを作成してみるで解説したとおりです。

LunaScriptSidebar.SetXml(LunaItemXmlBuilder.ToString())

LunaItemXmlBuilderのToStringメソッドを用いて追加したアイテムからXMLデータを作成し、LunaScriptSidebarのSetXmlメソッドを通じてXMLを登録しています。

LunaScriptSidebar.Update()

LunaScriptSidebarのUpdateメソッドを用いて、登録したアイテムがサイドバーに反映されます。

XSLスタイルシート解説


XSLスタイルシート

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rss="http://Apurl.org/rss/1.0/">
<xsl:output method="html" encoding="utf-8" />
<xsl:template match="/">
<html>
<head>
<base href="%BASE%" />
</head>
<body id=”oBody”>
<script for=”oSearchForm” event=”onsubmit()”>
LunaScriptSidebar.SetData(
“SearchWord”,
oSearchText.value);
LunaScriptSidebar.Execute(
“sample.vbs”,
“parse_youtube_result”);
</script>
<form id=”oSearchForm”>
<input type=”text” id=”oSearchText” size=”8″></input>

<input type=”submit” id=”oSubmitButton” value=”検索”></input>
</form>
<table>
<tr>
<td>
<img src=”./image/refresh.png”
onclick=”LunaScriptSidebar.Reload()”
alt=”更新” style=”cursor:hand;” />

</td>
</tr>
<xsl:apply-templates select=”opml/body/outline” />
</table>
</body>
</html>

</xsl:template>

<xsl:template match=”outline”>
<xsl:if test=”@type=’link'”>
<tr>
<td>
<div>

<a target=”_main”>
<xsl:attribute name=”href”>

<xsl:value-of select=”@htmlUrl” />
</xsl:attribute>
<img>
<xsl:attribute name=”src”>

http://img.youtube.com/vi/
<xsl:value-of select=”@htmlUrl” />
/2.jpg
</xsl:attribute>
</img>
</a>
</div>

<div>
<a target=”_main”>
<xsl:attribute name=”href”>

<xsl:value-of select=”@htmlUrl” />
</xsl:attribute>
<xsl:value-of select=”./@text” />

</a>
</div>

</td>
</tr>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

スタイルシートの解説

<script for="oSearchForm" event="onsubmit()">
LunaScriptSidebar.SetData(
"SearchWord",
oSearchText.value);
LunaScriptSidebar.Execute(
"sample.vbs",
"parse_youtube_result");
</script>
<form id="oSearchForm">
<input type="text" id="oSearchText" size="8"></input>
<input type="submit" id="oSubmitButton" value="検索"></input>
</form>

検索フォームを用意して、入力された検索語句でコンテントを更新するHTMLを生成しています。

<form>のonsubmitイベントにLunaScriptSidebarオブジェクトを利用してサイドバーを更新するスクリプトを関連付けています。

LunaScriptSidebar.SetData(
"SearchWord",
oSearchText.value);

LunaScriptSidebarオブジェクトのSetDataメソッドを利用してスクリプトが汎用的に利用するデータを格納しています。

“SearchWord”という名前でコンテントを更新するための検索語句を格納するために用いています。

格納した値は”SearchWord”を引数にしてGetDataメソッドを呼び出すことで取得できます。

LunaScriptSidebar.Execute(
"sample.vbs",
"parse_youtube_result");

LunaScriptSidebarオブジェクトのExecuteメソッドを利用してスクリプトを実行しています。

フレームワークは”sample.vbs”を”プラグインのルートディレクトリ\scripts”から読み込み、parse_youtube_result関数を実行します。

parse_youtube_result関数がTrueを返すとコンテントが更新されます。

<img>
<xsl:attribute name="src">
http://img.youtube.com/vi/
<xsl:value-of select="@htmlUrl" />
/2.jpg
</xsl:attribute>
</img>

ビデオクリップのサムネイルを表示する<img>タグを組み立てている行です。

スクリプトが追加したアイテムのURLにはビデオクリップのIDのみが登録されています。

スタイルシートではビデオクリップのサムネイルのURLが”img.youtube.com/vi/ビデオクリップのID/2.jpg”という形式になっていることを利用してURLを組み立てています。

<a target="_main">
<xsl:attribute name="href">

<xsl:value-of select="@htmlUrl" />
</xsl:attribute>
<xsl:value-of select="./@text" />
</a>

ビデオクリップへのリンクとなる<a>タグを組み立てている行です。

ビデオクリップのURLが”www.youtube.com/watch?v=ビデオクリップのID”という形式になっていることを利用してURLを組み立てています。

また、ターゲット名には”_main”を指定しています。”_main”とすることでクリックしたリンクはLunascapeで表示されます。

スクリプトサイドバープラグインリファレンス