質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

YouTube

YouTubeとはユーザーがビデオをアップロード・共有・閲覧できるビデオ共有ウェブサイトです。

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

2回答

3587閲覧

YouTubeの動画再生をフォームアプリケーション上で行い、アプリ側から制御したい

AiharaGames

総合スコア1

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

YouTube

YouTubeとはユーザーがビデオをアップロード・共有・閲覧できるビデオ共有ウェブサイトです。

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

1グッド

1クリップ

投稿2021/11/19 10:28

前提・実現したいこと

・YouTubeの動画再生をフォームアプリケーション上で行いたい
・読み込んだYouTube動画の「再生」「停止」「音量変更」をアプリケーション側から制御できるようにしたい。

上記を実現できるWindowsフォームアプリを作成したいのですが、後述の問題で実装できませんでした。
ネット上で調べても解決策が発見できなかったため、知恵をお借り出来たらと思い、質問させていただきました。

開発環境

VisualStudio 2019 C# フォームアプリケーション(.Net)

現状実現できているもの・実現具合

① YouTube動画をダウンロードしてメディアプレイヤーやDirectXで再生

これは実装出来ましたが、下記問題が残るためNG案となりました。

・ダウンロードに時間がかかる。 ・そもそもYouTubeは公式のPremiumサービス以外でのダウンロードを規約で禁じている

② ブラウザを埋め込み、下記Youtube IFrame API を用いて表示

こちらも実装できましたが、調べても「アプリケーション側から音量等を制御する方法」が分かりませんでした。
Youtube IFrame API: https://developers.google.com/youtube/player_parameters?hl=ja

該当のソースコード

ダウンロードの方はそもそも規約違反なのでブラウザ埋め込みの方を記載します。
ブラウザにはChromiumを使用しています。
下記はテスト用に、フォーム上にChromiumを置いただけのアプリとなっています。

  • Form1.cs

C#

1using System; 2using System.IO; 3using System.Threading; 4using System.Threading.Tasks; 5using System.Windows.Forms; 6using CefSharp.WinForms; 7 8namespace TestYoutubePlayer 9{ 10 public partial class Form1 : Form 11 { 12 public Form1() 13 { 14 InitializeComponent(); 15 string curDir = Directory.GetCurrentDirectory(); 16 Uri uri = new Uri(String.Format("file:///{0}/playPage.html", curDir)); 17 18 this.chromiumWebBrowser1.LoadUrl(uri.ToString()); 19 } 20 } 21}
  • playPage.html

HTML

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="Content-Type" content="text/html; utf-8"> 6 <meta http-equiv="Content-Script-Type" content="text/javascript"> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 <title>YouTubeViewer</title> 9</head> 10<body> 11 <div id="player"></div> 12 <script type="text/javascript" src="javascriptの絶対パス"></script> 13</body> 14</html>
  • script.js

javascript

1// 2. This code loads the IFrame Player API code asynchronously. 2var tag = document.createElement('script'); 3 4tag.src = "https://www.youtube.com/iframe_api"; 5var firstScriptTag = document.getElementsByTagName('script')[0]; 6firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 7 8// 3. This function creates an <iframe> (and YouTube player) 9// after the API code downloads. 10var player; 11function onYouTubeIframeAPIReady() { 12 player = new YT.Player('player', { 13 height: '360', 14 width: '640', 15 videoId: 'YouTubeのvideoID', 16 events: { 17 'onReady': onPlayerReady, 18 } 19 }); 20} 21 22// 4. The API will call this function when the video player is ready. 23function onPlayerReady(event) { 24 event.target.playVideo(); 25}

解決の方向性

現状で最も実現に近いのが上記のブラウザを用いた方法のため、そちらを記載しましたが、ブラウザにこだわる必要はありません。
どんな方法でも(利用するサービスすべての規約に引っかからないものに限る)目的の機能を実装できれば問題ありません。
実装方法に心当たりがありましたら、ご協力お願いいたします。

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ネット上で調べても解決策が発見できなかったため、知恵をお借り出来たらと思い、質問させていただきました。

ku__ra__geさんも指摘されていますが、質問のリンクの前(上?)のページにあります。

iframe 組み込みの YouTube Player API リファレンス - 動画の再生 |  YouTube IFrame Player API

iframe 組み込みの YouTube Player API リファレンス - プレーヤーの音量の変更 |  YouTube IFrame Player API

実装方法に心当たりがありましたら、ご協力お願いいたします。

特に心当たりはありませんが、ちょっと面白そうなのでやってみました。
なんでもいいということですので、WebView2を使用しました(CefSharpは以前苦戦して苦手意識がある^^;
WinForms アプリでの WebView2 の使用を開始する - Microsoft Edge Development | Microsoft Docs

cs

1using System; 2using System.Diagnostics; 3using System.IO; 4using System.Windows.Forms; 5using Microsoft.Web.WebView2.Core; 6 7namespace Questions370144 8{ 9 public partial class Form1 : Form 10 { 11 private bool playing; 12 private bool seeking; 13 14 public Form1() 15 { 16 InitializeComponent(); 17 InitializeAsync(); 18 } 19 20 private async void InitializeAsync() 21 { 22 await webView21.EnsureCoreWebView2Async(null); 23 24 webView21.CoreWebView2.WebMessageReceived += CoreWebView2_WebMessageReceived; 25 26 var html = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "index.html"); 27 webView21.CoreWebView2.Navigate(new Uri(html).AbsoluteUri); 28 } 29 30 private void CoreWebView2_WebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e) 31 { 32 var str = e.TryGetWebMessageAsString(); 33 Debug.WriteLine(str); 34 35 switch (str.Split(',')[0]) 36 { 37 case "UNSTARTED": 38 progressBar1.Value = 0; 39 progressBar1.Maximum = int.Parse(str.Split(',')[1]); 40 break; 41 case "ENDED": 42 timer1.Stop(); 43 playing = false; 44 break; 45 case "PLAYING": 46 timer1.Start(); 47 playing = true; 48 break; 49 case "PAUSED": 50 timer1.Stop(); 51 playing = false; 52 break; 53 case "BUFFERING": break; 54 //case "CUED": break; 55 } 56 } 57 58 private void button1_Click(object sender, EventArgs e) 59 { 60 webView21.CoreWebView2.ExecuteScriptAsync($"playVideo()"); 61 } 62 63 private void button2_Click(object sender, EventArgs e) 64 { 65 webView21.CoreWebView2.ExecuteScriptAsync($"pauseVideo()"); 66 } 67 68 private void trackBar1_Scroll(object sender, EventArgs e) 69 { 70 webView21.CoreWebView2.ExecuteScriptAsync($"setVolume({trackBar1.Value})"); 71 } 72 73 private void checkBox1_CheckedChanged(object sender, EventArgs e) 74 { 75 if (checkBox1.Checked) 76 { 77 checkBox1.Text = "🔇"; 78 webView21.CoreWebView2.ExecuteScriptAsync($"mute()"); 79 } 80 else 81 { 82 checkBox1.Text = "🔊"; 83 webView21.CoreWebView2.ExecuteScriptAsync($"unMute()"); 84 } 85 } 86 87 private void progressBar1_MouseDown(object sender, MouseEventArgs e) 88 { 89 seeking = true; 90 timer1.Stop(); 91 92 var value = (int)(e.X / (double)progressBar1.Width * progressBar1.Maximum); 93 progressBar1.Value = value; 94 webView21.CoreWebView2.ExecuteScriptAsync($"seekTo({value}, false)"); 95 } 96 97 private void progressBar1_MouseUp(object sender, MouseEventArgs e) 98 { 99 seeking = false; 100 if (playing) timer1.Start(); 101 102 var value = (int)(e.X / (double)progressBar1.Width * progressBar1.Maximum); 103 progressBar1.Value = value; 104 webView21.CoreWebView2.ExecuteScriptAsync($"seekTo({value}, true)"); 105 } 106 107 private void progressBar1_MouseMove(object sender, MouseEventArgs e) 108 { 109 if (seeking) 110 { 111 var value = (int)(e.X / (double)progressBar1.Width * progressBar1.Maximum); 112 progressBar1.Value = value; 113 webView21.CoreWebView2.ExecuteScriptAsync($"seekTo({value}, false)"); 114 } 115 } 116 117 private async void timer1_Tick(object sender, EventArgs e) 118 { 119 var str = await webView21.CoreWebView2.ExecuteScriptAsync($"getCurrentTime()"); 120 Debug.WriteLine(str); 121 122 if (double.TryParse(str.Trim('"'), out var value)) progressBar1.Value = (int)value; 123 } 124 } 125}

Form1.Designer.csまで入れると、1万字を超えてしまうので省略します。
以下のコントロールがあるとする(イベントも適宜設定のこと)

  • WebView2 webView21
  • Button button1(再生ボタン)
  • Button button2(ポーズボタン)
  • CheckBox checkBox1(ミュートトグルボタン)
  • TrackBar trackBar1(音量)
  • ProgressBar progressBar1(シークバー)
  • Timer timer1(シークバーを進めるタイマ)

html:index.html

1<!DOCTYPE html> 2<html> 3<body> 4 <div id="player"></div> 5 6 <script> 7 var tag = document.createElement('script'); 8 9 tag.src = "https://www.youtube.com/iframe_api"; 10 var firstScriptTag = document.getElementsByTagName('script')[0]; 11 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 12 13 var player; 14 function onYouTubeIframeAPIReady() { 15 player = new YT.Player('player', { 16 height: '360', 17 width: '640', 18 videoId: 'M7lc1UVf-VE', 19 playerVars: { controls: 0 }, 20 events: { 21 'onReady': onPlayerReady, 22 'onStateChange': onPlayerStateChange 23 } 24 }); 25 } 26 27 function onPlayerReady(event) { 28 event.target.playVideo(); 29 } 30 31 function onPlayerStateChange(event) { 32 if (event.data == YT.PlayerState.UNSTARTED) { 33 chrome.webview.postMessage('UNSTARTED,' + player.getDuration().toString()); 34 } else if (event.data == YT.PlayerState.ENDED) { 35 chrome.webview.postMessage('ENDED'); 36 } else if (event.data == YT.PlayerState.PLAYING) { 37 chrome.webview.postMessage('PLAYING'); 38 } else if (event.data == YT.PlayerState.PAUSED) { 39 chrome.webview.postMessage('PAUSED'); 40 } else if (event.data == YT.PlayerState.BUFFERING) { 41 chrome.webview.postMessage('BUFFERING'); 42 //} else if (event.data == YT.PlayerState.CUED) { // これいつ来るんだろう? 43 //chrome.webview.postMessage('CUED,' + player.getDuration().toString()); 44 } else { 45 chrome.webview.postMessage(event.data.toString()); 46 } 47 } 48 49 //function loadVideoById(videoId) { player.loadVideoById(videoId); } // loadVideoByIdはイベントが来ずいきなり再生される 50 function cueVideoById(videoId) { player.cueVideoById(videoId); } // こっちのほうがいい 51 function playVideo() { player.playVideo(); } 52 function pauseVideo() { player.pauseVideo(); } 53 function stopVideo() { player.stopVideo(); } 54 function setVolume(volume) { player.setVolume(volume); } // 0~100 の整数値 55 function mute() { player.mute(); } 56 function unMute() { player.unMute(); } 57 function getPlayerState() { return player.getPlayerState().toString(); } 58 function getCurrentTime() { return player.getCurrentTime().toString(); } 59 function seekTo(seconds, allowSeekAhead) { player.seekTo(seconds, allowSeekAhead); } 60 </script> 61</body> 62</html>

一応ひと通りの操作はできましたが、確認は雑なので何かエラーが出るかもしれません。

アプリ画像

投稿2021/11/19 21:58

編集2023/07/29 08:52
TN8001

総合スコア9321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AiharaGames

2021/11/20 01:27

回答ありがとうございます! アプリケーション側からブラウザ内のJavascriptの関数を叩けるとは思いませんでした。 WebView2は使ったことないので、まずは試してみようと思います! ありがとうございます!
AiharaGames

2021/11/20 18:45

テストアプリを作成したところ、目的の動作を実装することが出来ました! 詳しく記載いただき、非常に分かりやすかったので、ベストアンサーとさせていただきます。 ご協力ありがとうございました!
guest

0

② ブラウザを埋め込み、下記Youtube IFrame API を用いて表示

こちらも実装できましたが、調べても「アプリケーション側から音量等を制御する方法」が分かりませんでした。

リファレンスに書いてある setVolume を使えばいいと思います。

投稿2021/11/19 11:20

ku__ra__ge

総合スコア4524

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AiharaGames

2021/11/20 01:23

回答ありがとうございます! あれはJavascript側から使うものだと思っていたのですが、アプリケーション側からも叩けたのですね。 TN8001さんが具体的な使い方まで書いてくださったので、試してみようと思います。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問