JavaFX in RPi 〜IFrame Youtube Player自動再生〜

今回は、以前作成したプロパティファイルを読み込む処理を連携して、以下のような処理を作成したいと思います。

  1. プロパティファイルを読み込む
  2. 取得したURLを15秒おきに再生

前回JavaFXでHTML+JSで作成した Youtube Playerを表示しました。

ポイント

  1. JavaFXでプロパティファイルを読み込みます
  2. 読み込んだデータをJSに出力します。
    engine.executeScript("var data = " + videoIds + ";");
  3. あとはHTML(+JS)でVideoIDの数だけ動画をループして表示します。

HTMLに実装したJSはこのページをコピって作成しました

作成したコードはGithubにアップしてあります。

  1. Main.java
  2. iframePlayer.html

とりあえず、JSでYoutubeの動画を15秒ずつ切り替えるところが大変でした。

動画の指定方法として、URLではなくVideoIDを使用するところがキーポイントでした。

でわでわ。。。

https://github.com/ZenryokuService/RPiMediaPlayer/blob/master/RPiMediaPlayer/src/application/iframePlayer.html

JavaFX in RPi 〜IFrame Youtube Player を作る〜

今回はHTML(とJS)でYoutubePlayerを作成します。
目的と実行手順は以下の通りです。

参考サイトはこちらのGoogle Developperページです。

IFrame Youtube Player

  1. HTMLでYoutubePlayerを作成
  2. JavaFXで作成したHTMLをロード
  3. RPiで起動するように設定
  4. TVなどで再生してみれるようにする

サンプルコードをコピペで動かしてみました。

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '360', // window.innerHeight * 0.9などで値を変更する
          width: '640',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

しかし、このままだと全画面表示でないのでカスタムしてやる必要があります。

カスタムする

ここで、変更したいのはボタンなどをつけて「チャンネルなどを変えることができる」ということをユーザーに気づいてもらえるようにすることです。
具体的には下のようなイメージです。。。
しかし、仮の状態です。

「▶︎」などをつけてみました。
とりあえずは、見た目のみです。

バージョンについて

今回作成するのは、特定のYoutubeの動画IDを15秒おきに再生するものを作成するので、正直のところは「▶︎」ボタンなどはいらないのです。。。
しかし、バージョンわけで表示できるような工夫をしてみたいと思います。
<Version1>
Youtubeを15置きに動画IDを変更して連続的に再生する、アプリが止まるまで続ける自動再生プレーヤ

<Version2>
Youtubeだけでなく、インターネットTVなど表示するテレビ局などを変更、チャンネルの変更などができるようにする。
当然、RPi(ラズパイ)をテレビに接続して表示できるようにする。(試行錯誤中ですが・・・・)

以上のように考えております。

でわでわ。。。



JavaFX in RPi 〜HTMLをロードする〜

今回は作成したHTMLファイルをJavaFXでロードします。
前回URLをロードしてみた結果、表示したくない部分も画面に出てきたのでそれをなくします。

問題と解決策

早い話が、HTMLにiframeを使用して動画部分のみを表示しようというところです。
下の画像がJavaFXでロードした結果です。

HTMLをロードする

JavaFXでHTMLをロードするのはとても簡単でした。
<ロードした結果>

<ロードしたHTML>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
    <iframe width="560" height="315"
         src="https://www.youtube.com/embed/S0LbTzCrkiw"
         frameborder="0"
         allow="accelerometer;
         autoplay;
         encrypted-media;
         gyroscope;
         picture-in-picture"
         allowfullscreen>
    </iframe>
</body>

</html>

<Javaコード>

public void start(Stage primaryStage) {
    try {
        // レイアウト(土台)になるペインを作成
        BorderPane root = new BorderPane();

        // WebView(ブラウザ)の作成
        WebView browser = new WebView();
        WebEngine engine = browser.getEngine();
        String aaa = getClass().getResource("iframe.html").toExternalForm();
        System.out.println(aaa);
        engine.load(aaa);

        root.setCenter(browser);
        // 画面を表示する土台(シーン)を作成
        Scene scene = new Scene(root,this.windowWidth,this.windowHeight);
        // JavaFX用のCSSを読み込む
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.setOnCloseRequest(event -> Platform.exit());
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

今回の課題

ロードしたHTMLファイルのプロパティ(画面サイズや、そのほかのコントロール)を操作したい

上の要件を満たすために、通常のHTML + JSで実装するのであれば、シンプルにHTMLファイルに全部記述してしまうのが手っ取り早く、メンテナンス性も優れています。

というわけで、Youtubeを単純に全画面表示する場合は下のようなHTMLファイルを作成してやればOKな感じでした。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body width="100%" height="100%">
    <iframe style="border: 0; position:fixed; top:0; left:0; right:0; bottom:0; width:100%; height:100%"
         src="https://www.youtube.com/embed/S0LbTzCrkiw"
         frameborder="0"
         allow="accelerometer;
         autoplay;
         encrypted-media;
         gyroscope;
         picture-in-picture"
         allowfullscreen>
    </iframe>
</body>

</html>

しかし、自動再生が走らないのでちょいといじります。
iframeタグのsrcにautoplay=1を、allow属性にallow="accelerometer"を追加しました。HTMLを直接開いた場合は自動再生が始まらなかったのですが、JavaFXでロードしたら自動再生が始まりました。

ちょっと腑に落ちませんが、まぁよしとします(笑)

作成したコードはこちらにアップしてあります。

でわでわ。。。



JavaFX in RPi 〜URLでYoutubeにアクセス〜

JavaFXでのWeb画面表示をやろうと思います。
・参考にするのはORACLEのJavaドキュメント(日本語)です、このページはWebViewクラスの使い方が記載してありました。

・もう1つ使うものがあります。BorderPaneクラスです。
のクラスの使い方はこちらのページにありました

WebView & BorderPane

実行することは以下のような内容らしいです。

  1. ローカルおよびリモートURLからのHTMLコンテンツのレンダリング
  2. Web履歴の取得
  3. JavaScriptコマンドの実行
  4. JavaScriptからJavaFXへのアップコールの実行
  5. Webポップアップ・ウィンドウの管理
  6. 埋込みブラウザへの効果の適用

基本的な使い方は下のようなコードでやるようです。

WebView browser = new WebView();
WebEngine webEngine = browser.getEngine();
webEngine.load("http://mySite.com");

URLでYoutubeへ。。。

それではシンプルに実装してみます。以前やったプロパティファイルの読み込みと画面サイズの取得はそれぞれ以下のメソッドに実装しています。
・initWindowInfo(画面サイズの取得)
・loadProperties(プロパティファイルの読み込み)

ちなみにコードはGithubにアップしています。

上にあるWebViewの使い方を真似してURLを以下のものを指定して表示します。
https://www.youtube.com/watch?v=6qhJsvpd0ds

ちなみに、動画は下のようなものです。

しかし、実行結果は下のような見た目です。

コードは以下に。。。
ちなみにコードはGithubにアップしています。

public class Main extends Application {
    /** プロパティファイル */
    private Properties prop;
    /** プロパティファイルのキー・セット */
    private Set keySet;
    /** 最大ウィンドウサイズ(幅) */
    private double windowWidth;
    /** 最大ウィンドウサイズ(高さ) */
    private int windowHeight;

    @Override
    public void start(Stage primaryStage) {
        try {
            // レイアウト(土台)になるペインを作成
            BorderPane root = new BorderPane();

            // WebView(ブラウザ)の作成
            WebView browser = new WebView();
            WebEngine engine = browser.getEngine();
            engine.load("https://www.youtube.com/watch?v=6qhJsvpd0ds");

            root.setCenter(browser);
            // 画面を表示する土台(シーン)を作成
            Scene scene = new Scene(root,this.windowWidth,this.windowHeight);
            // JavaFX用のCSSを読み込む
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    /** コンストラクタ */
    public Main() {
        windowWidth = 0;
        windowHeight = 0;
        // プロパティファイルの読み込み
        prop = new Properties();
        loadProperties();
        // ウィンドウ情報の取得(縦横の幅)
        initWindowInfo();
    }
      ・
      ・
      ・

問題

表示したいのは動画のみでページ全体ではない

これをなんとかするのに頭を一捻りする必要があります。。。

頭から煙が出てきたのでそろそろと失礼します。

でわでわ。。。



Java FX in RPi 〜画面サイズの取得〜

今回は、起動しているPCの画面サイズを取得する実装を行います。なかなかJavaFXならではの実装にたどり着きませんが、必要な実装ですのでやります。

画面サイズの取得

画面サイズを取得する前に、予備知識として記載します。
Javaの画面関連のパッケージはjava.awtというものですが、OSを起動した時に画面を表示するのに使用している(グラフィック担当)サーバーがあり、それをXサーバー(X-Server)と言います。X-Window Systemのことです、常駐アプリで「表示してください」というリクエストに応えるので「サーバー」です。

java.awtはX-Serverに依存

以前、CUIでラズパイを起動してからJavaFXで画面を表示しようと試みたところJavaFXはGUIモードでないと起動できないことを知りました。。。
つまりX-Serverが動かないとJavaFXも動かない・・・ということです。

画面サイズを取得する

画面サイズを取得するのに「java.awt」を使用します。
そして、実際に使用するクラスはGraphicsEnvironmentです。

テスト駆動なので。。。

まずは、テストケースから入ります。
シンプルな内容なのでテストもシンプルです。
<仕様>
画面のサイズを取得しMainクラスのフィールドにセットする
このメソッドを使用します。

これだけです。
なので作成するテストケースは下のようになります。

/** 画面サイズの取得テスト */
@Test
public void testInitWindowInfo() {
    // privateメソッドの呼び出し
    try {
        // メソッドの取得
        Method mes = target.getClass().getDeclaredMethod("initWindowInfo");
        // メソッドのアクセス範囲をpublicに変更
        mes.setAccessible(true);
        // メソッドの実行(引数も返り値もない
        mes.invoke(target);

    } catch (NoSuchMethodException | SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // テストの起動確認
    assertFalse(target.getWindowHeight() == 0);
    assertFalse(target.getWindowWidth() == 0);
}

そして、テストケースを作成する最中に実装も終わっていました。

/** コンストラクタ */
public Main() {
    prop = new Properties();
    windowWidth = 0;
    windowHeight = 0;
}

こんな感じです。

次回は、JavaFXの画面作成に着手したいと思います。

でわでわ。。。