Как управлять Flash Player на YouTube с помощью C#?
Моя цель - сделать YouTube-плеер с открытым исходным кодом, которым можно управлять с помощью глобальных медиа-ключей. Глобальный ключевой вопрос, который я рассмотрел, но связь между плеером YouTube и моим приложением Windows Forms по какой-то причине просто не работает.
Пока это то, что у меня есть:
private AxShockwaveFlashObjects.AxShockwaveFlash player;
player.movie = "http://youtube.googleapis.com/v/9bZkp7q19f0"
...
private void playBtn_Click(object sender, EventArgs e)
{
player.CallFunction("<invoke name=\"playVideo\" returntype=\"xml\"></invoke>");
}
К сожалению это возвращает:
"Error HRESULT E_FAIL has been returned from a call to a COM component."
Что мне не хватает? Должен ли я загрузить другой URL?
В документации говорится, что проигрыватель YouTube использует класс ExternalInterface для управления им из JavaScript или AS3, поэтому он должен работать с C#.
ОБНОВЛЕНО:
Метод, используемый для встраивания проигрывателя: http://www.youtube.com/watch?v=kg-z8JfOIKw
Также пытался использовать JavaScript-API в элементе управления WebBrowser, но безуспешно (игрок просто не отвечал на команды JavaScript, пытался даже установить WebBrowser.url
на рабочем демо, все, что мне удалось, это получить onYouTubePlayerReady()
стрелять, используя простую встроенную версию объекта)
Я думаю, что могут быть некоторые проблемы безопасности, которые я наблюдаю, не знаю.
ОБНОВЛЕНИЕ 2:
любящее решение, см. мой ответ ниже.
4 ответа
После многих попыток и ударов головой я нашел решение:
Кажется, что Error HRESULT E_FAIL...
происходит, когда вспышка не понимает запрошенный вызов вспышки. Также для работы внешнего API YouTube можно включить JSI API:
player.movie = "http://www.youtube.com/v/VIDEO_ID?version=3&enablejsapi=1"
Как я уже сказал в этом вопросе, вся программа с открытым исходным кодом, поэтому вы найдете полный код в bitbucket.
Любые советы, предложения или соавторы высоко ценятся.
Полное решение:
Вот полное руководство по встраиванию и взаимодействию с плеером YouTube или любым другим флеш-объектом.
После просмотра видео урока установите флэш-плеер FlashCall
событие для функции, которая будет обрабатывать взаимодействие flash-> C# (в моем примере это YTplayer_FlashCall
)
сгенерированный `InitializeComponent()` должен быть:
...
this.YTplayer = new AxShockwaveFlashObjects.AxShockwaveFlash();
this.YTplayer.Name = "YTplayer";
this.YTplayer.Enabled = true;
this.YTplayer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("YTplayer.OcxState")));
this.YTplayer.FlashCall += new AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEventHandler(this.YTplayer_FlashCall);
...
обработчик событий FlashCall
private void YTplayer_FlashCall(object sender, AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEvent e)
{
Console.Write("YTplayer_FlashCall: raw: "+e.request.ToString()+"\r\n");
// message is in xml format so we need to parse it
XmlDocument document = new XmlDocument();
document.LoadXml(e.request);
// get attributes to see which command flash is trying to call
XmlAttributeCollection attributes = document.FirstChild.Attributes;
String command = attributes.Item(0).InnerText;
// get parameters
XmlNodeList list = document.GetElementsByTagName("arguments");
List<string> listS = new List<string>();
foreach (XmlNode l in list){
listS.Add(l.InnerText);
}
Console.Write("YTplayer_FlashCall: \"" + command.ToString() + "(" + string.Join(",", listS) + ")\r\n");
// Interpret command
switch (command)
{
case "onYouTubePlayerReady": YTready(listS[0]); break;
case "YTStateChange": YTStateChange(listS[0]); break;
case "YTError": YTStateError(listS[0]); break;
default: Console.Write("YTplayer_FlashCall: (unknownCommand)\r\n"); break;
}
}
это разрешит flash-> C# связь
вызов внешних функций flash (C#->flash):
private string YTplayer_CallFlash(string ytFunction){
string flashXMLrequest = "";
string response="";
string flashFunction="";
List<string> flashFunctionArgs = new List<string>();
Regex func2xml = new Regex(@"([a-z][a-z0-9]*)(\(([^)]*)\))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Match fmatch = func2xml.Match(ytFunction);
if(fmatch.Captures.Count != 1){
Console.Write("bad function request string");
return "";
}
flashFunction=fmatch.Groups[1].Value.ToString();
flashXMLrequest = "<invoke name=\"" + flashFunction + "\" returntype=\"xml\">";
if (fmatch.Groups[3].Value.Length > 0)
{
flashFunctionArgs = pars*emphasized text*eDelimitedString(fmatch.Groups[3].Value);
if (flashFunctionArgs.Count > 0)
{
flashXMLrequest += "<arguments><string>";
flashXMLrequest += string.Join("</string><string>", flashFunctionArgs);
flashXMLrequest += "</string></arguments>";
}
}
flashXMLrequest += "</invoke>";
try
{
Console.Write("YTplayer_CallFlash: \"" + flashXMLrequest + "\"\r\n");
response = YTplayer.CallFunction(flashXMLrequest);
Console.Write("YTplayer_CallFlash_response: \"" + response + "\"\r\n");
}
catch
{
Console.Write("YTplayer_CallFlash: error \"" + flashXMLrequest + "\"\r\n");
}
return response;
}
private static List<string> parseDelimitedString (string arguments, char delim = ',')
{
bool inQuotes = false;
bool inNonQuotes = false;
int whiteSpaceCount = 0;
List<string> strings = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in arguments)
{
if (c == '\'' || c == '"')
{
if (!inQuotes)
inQuotes = true;
else
inQuotes = false;
whiteSpaceCount = 0;
}else if (c == delim)
{
if (!inQuotes)
{
if (whiteSpaceCount > 0 && inQuotes)
{
sb.Remove(sb.Length - whiteSpaceCount, whiteSpaceCount);
inNonQuotes = false;
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
whiteSpaceCount = 0;
}
else if (char.IsWhiteSpace(c))
{
if (inNonQuotes || inQuotes)
{
sb.Append(c);
whiteSpaceCount++;
}
}
else
{
if (!inQuotes) inNonQuotes = true;
sb.Append(c);
whiteSpaceCount = 0;
}
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
return strings;
}
добавление обработчиков событий Youtube:
private void YTready(string playerID)
{
YTState = true;
//start eventHandlers
YTplayer_CallFlash("addEventListener(\"onStateChange\",\"YTStateChange\")");
YTplayer_CallFlash("addEventListener(\"onError\",\"YTError\")");
}
private void YTStateChange(string YTplayState)
{
switch (int.Parse(YTplayState))
{
case -1: playState = false; break; //not started yet
case 1: playState = true; break; //playing
case 2: playState = false; break; //paused
//case 3: ; break; //buffering
case 0: playState = false; if (!loopFile) mediaNext(); else YTplayer_CallFlash("seekTo(0)"); break; //ended
}
}
private void YTStateError(string error)
{
Console.Write("YTplayer_error: "+error+"\r\n");
}
использование ex:
YTplayer_CallFlash("playVideo()");
YTplayer_CallFlash("pauseVideo()");
YTplayer_CallFlash("loadVideoById(KuNQgln6TL0)");
string currentVideoId = YTplayer_CallFlash("getPlaylist()");
string currentDuration = YTplayer_CallFlash("getDuration()");
Функции YTplayer_CallFlash
, YTplayer_FlashCall
должен работать для любой связи flash-C# с небольшими настройками, такими как YTplayer_CallFlash
переключатель (команда).
Похоже, вы пытаетесь использовать Adobe Flash в качестве интерфейса; затем передать определенные переменные обратно в C#.
Пример будет такой:
Во Flash; создать кнопку... Actionscript:
on (press) {
fscommand("Yo","dude");
}
Затем Visual Studio вам просто нужно добавить ссылку на объект COM: Shockwave Flash Object
Затем установите для вставки значение true;
Тогда внутри Visual Studio вы сможете перейти в Свойства; найти команду Команда fscom позволит вам физически подключить значение из фильма Flash.
AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent
Что собирает; тогда просто используйте e.command
а также e.arg
например, чтобы собранный предмет что-то сделал.
Затем добавьте это в EventHandler;
lbl_Result.Text="The "+e.args.ToString()+" "+e.command.ToString()+" was clicked";
И бум, он передает свои данные из Flash в Visual Studio. Не нужно никаких сумасшедших сложных розеток.
На боковой ноте; если у вас есть Flash внутри Visual Studio, ключ должен убедиться, что для "embed установлено значение true". Это будет содержать все ссылки на пути внутри Flash-объекта; чтобы избежать любых неправильных путей.
Я не уверен, что это ответ, который вы ищете; или отвечает на ваш вопрос. Но без более подробной информации о вашей цели / ошибке. Я не могу вам помочь.
Надеюсь это поможет. Первая часть должна фактически показать вам лучший способ встроить вашу Shockwave в Visual Studio.
Убедитесь, что вы добавили правильную ссылку:
- Внутри вашего проекта откройте "Solution Explorer"
- Щелкните правой кнопкой мыши, чтобы "Добавить ссылку"
- Перейти к "COM-объект"
Найти подходящий объект;
COM Objects:
Shockwave ActiveX
Flash Accessibility
Flash Broker
Shockwave Flash
Надеюсь, это поможет.
Похоже, вы неправильно встраиваете его; так что вы можете позвонить ему. Если я немного ошибаюсь; или это то, что вы имели в виду:
Если у вас возникли трудности, у Рыка была публикация; с помощью метода для вставки видео YouTube:
<% MyYoutubeUtils.ShowEmebddedVideo("<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>") %>
Или же...
public static string ShowEmbeddedVideo(string youtubeObject)
{
var xdoc = XDocument.Parse(youtubeObject);
var returnObject = string.Format("<object type=\"{0}\" data=\{1}\"><param name=\"movie\" value=\"{1}\" />",
xdoc.Root.Element("embed").Attribute("type").Value,
xdoc.Root.Element("embed").Attribute("src").Value);
return returnObject;
}
Что вы можете найти нить здесь: https://stackru.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp
Я прошу прощения, если мой пост кажется фрагментированным; но я не мог сказать, была ли это ссылка, переменная, метод или вставка, которые вызывали у вас трудности. Надеюсь, это поможет; или дайте мне больше деталей, и я соответствующим образом подправлю свой ответ.
Связь C# с ActionScript:
import flash.external.ExternalInterface;
ExternalInterface.addCallback("loadAndPlayVideo", null, loadAndPlayVideo);
function loadAndPlayVideo(uri:String):void
{
videoPlayer.contentPath = uri;
}
Тогда в C#; добавьте экземпляр элемента управления ActiveX и добавьте содержимое в конструктор.
private AxShockwaveFlash flashPlayer;
public FLVPlayer ()
{
// Add Error Handling; to condense I left out.
flashPlayer.LoadMovie(0, Application.StartupPath + "\\player.swf");
}
fileDialog = new OpenFileDialog();
fileDialog.Filter = "*.flv|*.flv";
fileDialog.Title = "Select a Flash Video File...";
fileDialog.Multiselect = false;
fileDialog.RestoreDirectory = true;
if (fileDialog.ShowDialog() == DialogResult.OK)
{
flashPlayer.CallFunction("<invoke" + " name=\"loadAndPlayVideo\" returntype=\"xml"> <arguements><string>" + fileDialog.FileName + "</string></arguements></invoke>");
}
Связь ActionScript с C#:
import flash.external.ExternalInterface;
ExternalInterface.call("ResizePlayer", videoPlayer.metadata.width, videoPlayer.metadata.height);
flashPlayer.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(flashPlayer_FlashCall);
Затем должен появиться XML:
<invoke name="ResizePlayer" returntype="xml">
<arguements>
<number> 320 </number>
<number> 240 </number>
</arguments>
</invoke>
Затем проанализируйте XML в обработчике событий и локально вызовите функцию C#.
XmlDocument document = new XmlDocument();
document.LoadXML(e.request);
XmlNodeList list = document.GetElementsByTagName("arguements");
ResizePlayer(Convert.ToInt32(list[0].FirstChild.InnerText), Convert.ToInt32(list[0].ChildNodes[1].InnerText));
Теперь они оба передают данные взад и вперед. Это основной пример; но при использовании ActionScript Communication у вас не должно быть проблем с использованием нативного API.
Надеюсь, что это более полезно. Вы можете расширить эту идею с помощью служебного класса для повторного использования. Очевидно, что приведенный выше код имеет некоторые ограничения; но, надеюсь, это направит вас в правильном направлении. В этом направлении ты пытался идти? Или я все еще упускаю суть?
Создать новый Flash-фильм; в ActionScript 3. Затем на начальном первом кадре; применить ниже:
Security.allowDomain("www.youtube.com");
var my_player:Object;
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"))
my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
function onLoaderInit(e:Event):void{
addChild(my_loader);
my_player = my_loader.content;
my_player.addEventListener("onReady", onPlayerReady);
}
function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
my_player.loadVideoById("_OBlgSz8sSM",0);
}
Так что именно делает этот скрипт? Он использует собственный API и использует ActionScript Communication. Так что ниже я буду разбивать каждую строку.
Security.allowDomain("www.youtube.com");
Без этой строки YouTube не будет взаимодействовать с объектом.
var my_player:Object;
Вы не можете просто загрузить фильм в фильм; поэтому мы создадим переменную Object. Вы должны загрузить специальный.swf, который будет содержать доступ к этим кодам. Нижеприведенное; делает именно это. Таким образом, вы можете получить доступ к API.
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"));
Теперь мы ссылаемся на API Google в соответствии с их документацией.
my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
Но для того, чтобы реально работать с нашим объектом; нам нужно дождаться полной инициализации. Так что слушатель событий будет ждать; поэтому мы знаем, когда можем передать ему команды.
onLoaderInit
Функция будет запущена при инициализации. Тогда это будет первое задание my_loader
отобразить список, чтобы появилось видео.
addChild(my_loader);
это то, что будет загружать один; my_player = my_loader.content;
будет хранить ссылку для быстрого доступа к объекту.
Хотя это было инициализировано; Вы должны ждать еще дальше... Вы используете my_player.addEventListener("onReady", onPlayerReady);
ждать и слушать эти пользовательские события. Что позволит более поздней функции обрабатывать.
Теперь плеер готов к базовой настройке;
function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
}
Вышеприведенная функция запускает очень простые манипуляции. Тогда последняя строка my_player.loadVideoById("_OBlgSz8sSM",0);
ссылается на конкретное видео.
Тогда на вашей сцене; Вы можете создать две кнопки и применить:
play_btn.addEventListener(MouseEvent.CLICK, playVid);
function playVid(e:MouseEvent):void {
my_player.playVideo();
}
pause_btn.addEventListener(MouseEvent.CLICK, pauseVid);
function pauseVid(e:MouseEvent):void {
my_player.pauseVideo();
}
Что даст вам функциональность воспроизведения и паузы. Некоторые дополнительные предметы вы можете использовать наши:
loadVideoById()
cueVideoById()
playVideo()
pauseVideo()
stopVideo()
mute()
unMute()
Имейте в виду, что их нельзя использовать или вызывать, пока они не будут полностью инициализированы. Но используя это; с помощью более раннего метода вы должны разметить цель и передать переменные между ними для манипуляции.
Надеюсь, это поможет.
Я бы начал с того, чтобы убедиться, что javascript может общаться с вашим flash-приложением.
убедитесь, что у вас есть: allowScriptAccess="sameDomain"
установить во встраивание (с http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html).
Вы должны проверить, что html->flash работает; тогда C->html; и постепенно работать до C->you-tube-component. у вас есть много потенциальных точек отказа между C и компонентом you-tube прямо сейчас, и трудно решить все из них одновременно.
Это поставило меня в тупик на несколько часов.
Просто добавьте enable JS на ваш URL:
http://www.youtube.com/v/9bZkp7q19f0?version=3& enablejsapi = 1
CallFunction прекрасно работает для меня сейчас! Также удалите ненужное место в вызове.