Electron 应用程序中无法播放 YouTube 视频,但在网站上可以播放

4

我正在处理两个相关的项目,一个网页和一个基于Electron的应用程序,它们都需要在嵌入式iframe中播放Youtube视频。在网站上一切都运行得很完美,

var newUrl = 'http://www.youtube.com/embed/' + $scope.youtube_parser(video.url);
        $scope.videoURL = $sce.trustAsResourceUrl(newUrl + '?enablejsapi=1&showinfo=0&rel=0');
$scope.setYTPlayer();

$scope.setYTPlayer = function(){
    $scope.player;
    $scope.player = new YT.Player('player', {
        height: '360',
        width: '640',
        videoId: $scope.videoSelected,
        events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
        }
    });
}
<iframe id="player" frameborder="0" allowfullscreen ng-src="{{videoURL}}" style="width: 100%;height: 100%;"></iframe>

但在Electron应用中,许多视频无法播放,播放器上会显示消息:"视频不可用"。
var youtubeId = $scope.getYoutubeId(video.url)
    $scope.currentVideo = $sce.trustAsResourceUrl(
      'https://www.youtube.com/embed/' + youtubeId + '?rel=0'
    )
<iframe width="100%" height="442" ng-src="{{ currentVideo }}" frameborder="0" allowfullscreen></iframe>

播放器截图

同样的链接和方法,在页面上复制没有任何问题。仅用 iframe,使用 api,更改播放参数问题仍然存在。问题是,是否有 YouTube 政策禁止在某些地方播放视频?或者可能是什么错误?

Electron 版本:v3.0.3

非常感谢,如果表达不清楚请多多包涵。


欢迎来到SO ;) 请阅读这篇关于如何提出好问题的文章。这包括一个恰当的描述,说明你想要实现什么,你的代码(或相关片段),以及你已经尝试过的努力。在你的情况下,我建议你通过阅读electron文档和教程来了解嵌入yt视频的一般方法,并尝试掌握你想要实现的目标。 - iLuvLogix
如果有些人可以播放而有些人不能,则这取决于YT视频的内容使用限制,例如您可以禁止嵌入。 - eckes
1个回答

3

这个问题是由于打开Electron窗口的协议引起的。

如果你打开一个本地的html文件,则会使用"file://"协议。

我找到了两个解决方案:

你可以启动一个本地临时http服务器来传输html文件到窗口,然后禁用它。

import http from 'http';
import fs from 'fs';
import path from 'path';

//at start
let server;
server = http.createServer((req, res) => {
const filePath = path.join(app.getAppPath(), 'public', req.url);
const file = fs.readFileSync(filePath);
res.end(file.toString());
if (req.url.includes('index.js'))
   server.close();
}).listen(8080);

//after app-ready event
mainWindow.loadURL('http://localhost:8080/index.html');

更好的选择是拦截http协议并传输文件,但在传输完所有本地文件后必须禁用拦截,否则会影响所有后续的http请求。
import path from 'path';

//before window.loadURL
session.defaultSession.protocol.interceptFileProtocol('http', (request, callback) => {
    const fileUrl = request.url.replace('http://localhost/', '');
    const filePath = path.join(app.getAppPath(), 'public', fileUrl);

    if(request.url.includes('index.js')) {
        session.defaultSession.protocol.uninterceptProtocol('http');
    }
    callback(filePath);
});
//after app-ready event
mainWindow.loadURL('http://localhost:8080/index.html');

此外,如果您遇到标题为“x-frame-options”=“sameorigin”的错误,您可以在收到响应后删除此标题。
const filter = {
    urls: ['https://www.youtube.com/*']
};
session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
    for (const header in details.responseHeaders) {
        if (header.toLocaleLowerCase() === 'x-frame-options') {
            delete details.responseHeaders[header];
        }
    }
    callback({ cancel: false, responseHeaders: details.responseHeaders });
});

它只是为我加载了一个空窗口。 - Systems Rebooter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接