如何使用HTML5仅播放YouTube视频的音频?

48

使用HTML 5和Javascript,是否可以仅播放来自YouTube视频的音频?


1
YouTube提供视频服务,因此只有视频从他们的服务器流传,除非他们有高度不可能的仅音频选项。 - Joseph
12个回答

45

更新2022

为演示添加了Webm格式。 您可以始终检查控制台日志并添加所需的所有格式。

更新2021

您可以解析YouTube HTML页面以获取特定视频的所有流,并提取仅包含音频的流。

以下是一个使用公共Google图像代理(但您可以使用任何免费或自己的CORS代理)的示例:

var vid = "3r_Z5AYJJd4",
  audio_streams = {},
  audio_tag = document.getElementById('youtube');

fetch("https://images" + ~~(Math.random() * 33) + "-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURIComponent("https://www.youtube.com/watch?hl=en&v=" + vid)).then(response => {
  if (response.ok) {
    response.text().then(data => {

      var regex = /(?:ytplayer\.config\s*=\s*|ytInitialPlayerResponse\s?=\s?)(.+?)(?:;var|;\(function|\)?;\s*if|;\s*if|;\s*ytplayer\.|;\s*<\/script)/gmsu;

      data = data.split('window.getPageData')[0];
      data = data.replace('ytInitialPlayerResponse = null', '');
      data = data.replace('ytInitialPlayerResponse=window.ytInitialPlayerResponse', '');
      data = data.replace('ytplayer.config={args:{raw_player_response:ytInitialPlayerResponse}};', '');


      var matches = regex.exec(data);
      var data = matches && matches.length > 1 ? JSON.parse(matches[1]) : false;

      console.log(data);

      var streams = [],
        result = {};

      if (data.streamingData) {

        if (data.streamingData.adaptiveFormats) {
          streams = streams.concat(data.streamingData.adaptiveFormats);
        }

        if (data.streamingData.formats) {
          streams = streams.concat(data.streamingData.formats);
        }

      } else {
        return false;
      }

      streams.forEach(function(stream, n) {
        var itag = stream.itag * 1,
          quality = false;
        console.log(stream);
        switch (itag) {
          case 139:
            quality = "48kbps";
            break;
          case 140:
            quality = "128kbps";
            break;
          case 141:
            quality = "256kbps";
            break;
          case 249:
            quality = "webm_l";
            break;
          case 250:
            quality = "webm_m";
            break;
          case 251:
            quality = "webm_h";
            break;
        }
        if (quality) audio_streams[quality] = stream.url;
      });

      console.log(audio_streams);

      audio_tag.src = audio_streams['256kbps'] || audio_streams['128kbps'] || audio_streams['48kbps'];
      audio_tag.play();
    })
  }
});
<audio id="youtube" autoplay controls loop></audio>

并不适用于所有的视频,非常依赖于货币化设置或类似的东西。


1
似乎YouTube在2019年9月更改了url_encoded_fmt_stream_mapadaptive_fmts。请见下面的我的文章......我稍作修改让你的解决方案工作起来了。 - Josh Stovall
对于这个YouTube ID bxnYFOixIoc,您的代码无法工作,因为它不包含URL。谢谢。 - MindRoasterMir
@MindRoasterMir 对于这个特定的视频,元响应中没有mp3格式。我猜这取决于用户代理或其他什么因素。如果需要,可以在控制台中使用Webm流。 - 350D
@350D,你的意思是我可以使用WebM替代MP3音频来播放音频吗?我尝试了一些链接,但没有成功,所以我想也许在你回答之后YouTube网站已经有所改变。我会尝试使用WebM来仅播放音频。谢谢。 - MindRoasterMir
@MindRoasterMir 你只能在支持的浏览器中使用webm链接(例如Firefox)。 - 350D
显示剩余3条评论

24

嵌入视频播放器并使用CSS隐藏视频。如果您做得当,甚至可以只隐藏视频而不隐藏下面的控件。

但是,我建议不要这样做,因为这将违反YouTube服务条款。如果您真的只想播放音频,请改用自己的服务器。


7
这是违反服务条款的行为:[禁止] 通过 YouTube API 获取的任何 YouTube 音视频内容的音频或视频组件,不能被分离、隔离或修改。 http://code.google.com/apis/youtube/terms.html - keyboardP
4
好的,那么我会上传一个黑色图片并使用黑色背景来展示视频 :D - user979830
34
那真的违反了YouTube的服务条款吗?就我所理解的而言,服务条款只涉及其API。嵌入视频播放器并使用CSS隐藏视频并没有使用YouTube API。因此,我认为这并不违反YouTube的服务条款。 - sabbir
1
所以,这是一个解决方案,但YouTube视频广告怎么办?即使您将其作为背景音乐,用户也会受到隐藏的音频广告的轰炸。 - Pete Adam Bialecki
2022年6月更新 对我来说没有任何方法可行,所以我决定寻找另一个解决方案,并找到了这个:https://codepen.io/gaffling/pen/YzebyrE - adilbo
显示剩余2条评论

9

更新至2020年

似乎在2019年9月,YouTube更新了get_video_info返回的值。

现在我们要找的是data.formatsdata.adaptiveFormats,而不是以前的data.url_encoded_fmt_stream_mapdata.adaptive_fmts(用于其他旧示例)。

无论如何,以下是您想要的一些代码,将YouTube视频加载到<audio>元素中在CodePen上尝试

// YouTube video ID
var videoID = "CMNry4PE93Y";

// Fetch video info (using a proxy to avoid CORS errors)
fetch('https://cors-anywhere.herokuapp.com/' + "https://www.youtube.com/get_video_info?video_id=" + videoID).then(response => {
  if (response.ok) {
    response.text().then(ytData => {
      
      // parse response to find audio info
      var ytData = parse_str(ytData);
      var getAdaptiveFormats = JSON.parse(ytData.player_response).streamingData.adaptiveFormats;
      var findAudioInfo = getAdaptiveFormats.findIndex(obj => obj.audioQuality);
      
      // get the URL for the audio file
      var audioURL = getAdaptiveFormats[findAudioInfo].url;
      
      // update the <audio> element src
      var youtubeAudio = document.getElementById('youtube');
      youtubeAudio.src = audioURL;
      
    });
  }
});

function parse_str(str) {
  return str.split('&').reduce(function(params, param) {
    var paramSplit = param.split('=').map(function(value) {
      return decodeURIComponent(value.replace('+', ' '));
    });
    params[paramSplit[0]] = paramSplit[1];
    return params;
  }, {});
}
<audio id="youtube" controls></audio>


你有任何想法为什么它对我不起作用吗?这里的代码片段也不起作用。它只显示一个音频播放器,但没有播放任何内容。在控制台中,你会得到这个错误:Failed to load resource: the server responded with a status of 403 (Forbidden, see https://cors-anywhere.herokuapp.com/corsdemo)。 - Johanna

9

你可以通过Youtube Iframe API制作假音频播放器来切换Youtube iframe, 并使用该API获取想要在音频播放器上显示的信息。 下面是我的示例。

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="player.css">
    <script src="https://www.youtube.com/iframe_api"></script>
    <script src="player.js"></script>
    <script>
        function onYouTubeIframeAPIReady() {
            player = new YT.Player('player', {
                height: '360',
                width: '640',
                videoId: 'M7lc1UVf-VE',
                events: {
                    'onReady': onPlayerReady,
                    'onStateChange': onPlayerStateChange
                }
            });
        }
    </script>
</head>
<body>
    <!--Youtube-->
    <div id="player" style="display: none; visibility: hidden;"></div>
    
    <!--Player-->
    <div class="audio-player">
        <div class="player-controls">
            <div id="radioIcon"></div>
            <button id="playAudio"></button>
            <div id="seekObjContainer">
                <div id="seekObj">
                    <div id="percentage"></div>
                </div>
            </div>
            <p><small id="currentTime">00:00</small></p>
        </div>
    </div>
</body>
</html>
player.js
var player;

function onPlayerReady(event) {
    document.getElementById(ui.play).addEventListener('click', togglePlay);
    timeupdater = setInterval(initProgressBar, 100);
}

function onPlayerStateChange(event) {
    if (event.data == YT.PlayerState.ENDED) {
        document.getElementById(ui.play).classList.remove('pause');
        document.getElementById(ui.percentage).style.width = 0;
        document.getElementById(ui.currentTime).innerHTML = '00:00';
        player.seekTo(0, true);
    }
}

let ui = {
    play: 'playAudio',
    audio: 'audio',
    percentage: 'percentage',
    seekObj: 'seekObj',
    currentTime: 'currentTime'
};

function togglePlay() {
    if (player.getPlayerState() === 1) {
        player.pauseVideo();
        document.getElementById(ui.play).classList.remove('pause');
    } else {
        player.playVideo();
        document.getElementById(ui.play).classList.add('pause');
    }
}
        
function calculatePercentPlayed() {
    let percentage = (player.getCurrentTime() / player.getDuration()).toFixed(2) * 100;
    document.getElementById(ui.percentage).style.width = `${percentage}%`;
}

function calculateCurrentValue(currentTime) {
    const currentMinute = parseInt(currentTime / 60) % 60;
    const currentSecondsLong = currentTime % 60;
    const currentSeconds = currentSecondsLong.toFixed();
    const currentTimeFormatted = `${currentMinute < 10 ? `0${currentMinute}` : currentMinute}:${
    currentSeconds < 10 ? `0${currentSeconds}` : currentSeconds
    }`;
    
    return currentTimeFormatted;
}

function initProgressBar() {
    const currentTime = calculateCurrentValue(player.getCurrentTime());
    document.getElementById(ui.currentTime).innerHTML = currentTime;
    document.getElementById(ui.seekObj).addEventListener('click', seek);

    function seek(e) {
        const percent = e.offsetX / this.offsetWidth;
        player.seekTo(percent * player.getDuration());
    }
    
    calculatePercentPlayed();
}
player.css
* {
    box-sizing: border-box;
}
body {
    background-size: 6px 6px !important;
    background-image: linear-gradient(-45deg, rgba(0, 0, 0, 0) 46%, coral 49%, coral 51%, rgba(0, 0, 0, 0) 55%);
    background-color: white;
    padding-top: 60px;
}
.audio-player {
    width: 470px;
    padding: 35px 20px;
    margin: auto;
    background-color: white;
    border: 1px solid black;
}
.audio-player .player-controls {
    position: relative;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.audio-player #radioIcon {
    width: 30px;
    height: 30px;
    background: url("https://img.icons8.com/ios/50/000000/microphone.png") no-repeat center;
    background-size: contain;
}
.audio-player #playAudio {
    -webkit-appearance: none;
    outline: none;
    cursor: pointer;
    border: none;
    width: 30px;
    height: 30px;
    background: url("https://img.icons8.com/play") no-repeat center;
    background-size: contain;
}
.audio-player #playAudio.pause {
    background: url("https://img.icons8.com/pause") no-repeat center;
    background-size: contain;
}
.audio-player p {
    margin: 0 0 0 5px;
    line-height: 1;
    display: inline-flex;
}
.audio-player p small {
    font-size: 10px;
}
.audio-player #seekObjContainer {
    position: relative;
    width: 300px;
    margin: 0 5px;
    height: 5px;
}
.audio-player #seekObjContainer #seekObj {
    position: relative;
    width: 100%;
    height: 100%;
    background-color: #e3e3e3;
    border: 1px solid black;
}
.audio-player #seekObjContainer #seekObj #percentage {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    background-color: coral;
}

音频播放器来自这里。 希望这能帮到大家!!

8
这可能是一篇旧帖子,但仍然有人可能在搜索相关内容,所以在这里提供给大家:

这可能是一篇旧帖子,但仍然有人可能在搜索相关内容,所以在这里提供给大家:

<div style="position:relative;width:267px;height:25px;overflow:hidden;">
<div style="position:absolute;top:-276px;left:-5px">
<iframe width="300" height="300" 
  src="https://www.youtube.com/embed/youtubeID?rel=0">
</iframe>
</div>
</div>

5

VIDEO_ID是你的YouTube视频的实际ID。

<div data-video="VIDEO_ID"  
        data-autoplay="0"         
        data-loop="1"             
        id="youtube-audio">
 </div>

 <script src="https://www.youtube.com/iframe_api"></script>
 <script src="https://cdn.rawgit.com/labnol/files/master/yt.js"></script>

1
感谢这个答案。有没有一种方法可以在特定的时间开始和停止音频?应该使用哪些属性? - Tora Tora Tora
1
您可以通过在YouTube URL中添加这些查询参数来实现:start=00:30&end=03:20 - uraniumreza

2
答案很简单: 使用像jwplayer或类似的第三方产品, 然后将其设置为最小播放器大小,即音频播放器大小(仅显示播放器控件)。 完成。 我已经使用了8年以上。

8
这并没有为现有的答案增添任何内容。 - David
6
当然可以。它让我们知道jwplayer是一个可行的选择。 - Zoran Pavlovic
7
“使用HTML5和JavaScript”不是一个可行的替代方案。 - Olathe
这仍然会消耗您的数据流量来观看视频吗? - Max Alexander Hanna

0

var vid = "bpt84ceWAY0",
    audio_streams = {},
    audio_tag = document.getElementById('youtube');

fetch("https://"+vid+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=https%3A%2F%2Fwww.youtube.com%2Fget_video_info%3Fvideo_id%3D" + vid).then(response => {
    if (response.ok) {
        response.text().then(data => {

            var data = parse_str(data),
                streams = (data.url_encoded_fmt_stream_map + ',' + data.adaptive_fmts).split(',');

            streams.forEach(function(s, n) {
                var stream = parse_str(s),
                    itag = stream.itag * 1,
                    quality = false;
                console.log(stream);
                switch (itag) {
                    case 139:
                        quality = "48kbps";
                        break;
                    case 140:
                        quality = "128kbps";
                        break;
                    case 141:
                        quality = "256kbps";
                        break;
                }
                if (quality) audio_streams[quality] = stream.url;
            });

            console.log(audio_streams);

            audio_tag.src = audio_streams['128kbps'];
            audio_tag.play();
        })
    }
});

function parse_str(str) {
    return str.split('&').reduce(function(params, param) {
        var paramSplit = param.split('=').map(function(value) {
            return decodeURIComponent(value.replace('+', ' '));
        });
        params[paramSplit[0]] = paramSplit[1];
        return params;
    }, {});
}
<audio id="youtube" autoplay controls loop></audio>


0

除了提到jwplayer和可能的TOS违规外,我想链接到github上的以下存储库:YouTube音频播放器生成库,它允许生成以下输出:

enter image description here

该库支持播放列表和PHP自动渲染,可通过视频URL和配置选项实现。


6
链接很好,但它使用的是Flash播放器,而不是HTML5。 - mbomb007
@mbomb007,好发现,完全忘记了标题中的HTML5!我还是会留下答案,因为如果人们没有HTML-only的要求,他们仍然可能会着陆在这个页面上。 - berezovskyi

0

我同意Tom van der Woerdt的观点。你可以使用CSS来隐藏视频(在高度限制的div包装器中使用visibility:hidden或overflow:hidden),但这可能会违反Youtube的政策。此外,你如何控制音频(暂停、停止、音量等)?

相反,你可以利用http://www.houndbite.com/等资源来管理音频。


其他资源似乎是最好的解决方案。 - user979830

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