手机上的Soundcloud嵌入式播放器 [英] Soundcloud embedded player on mobile

查看:260
本文介绍了手机上的Soundcloud嵌入式播放器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是HTML页面上的SoundCloud嵌入式播放器在移动设备上的外观:



这很烦人,因为用户必须点击在浏览器中监听,然后,它通常不会像应该那样启动,因此用户必须单击暂停按钮和播放。



如何拥有正常的外观,即使是在移动设备上?






这里是嵌入code:

 < iframe width =100%height =166scrolling =noframeborder =no SRC =https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/271188615&amp;color=ff5500&a熔点; auto_play =假放大器;放大器; hide_related =假放大器;放大器; show_comments =真放大器;放大器; show_user =真放大器;放大器; show_reposts =假>< / iframe中> 


解决方案

我会建议不要使用嵌入式iframe玩家,而是使用



我将分解使用声音云API的基本步骤来完成此操作。

幸运的是,回放非常简单。您可以跳过所有认证要求。因为您使用的任何端点都不需要身份验证。



您只需要一个客户端ID来发出请求。 我建议注册一个带有声音云的应用程序,但是您可以像我一样使用嵌入式播放器的客户端ID。

注意:嵌入式播放器使用客户端ID - > cUa40O3Jg3Emvp6Tv4U6ymYYO50NUGpJ



这个实现的基础是 tracks 端点:$ b​​ $ b < a href =https://developers.soundcloud.com/docs/api/reference#tracks =nofollow noreferrer> https://developers.soundcloud.com/docs/api/reference#tracks

这个端点给了我们几乎所有我们需要的东西:


  • streaming url li>
  • 标题,艺术家姓名
  • 艺术品



缺少一件事,那就是波形数据点显示SoundCloud的品牌识别波形。

获取这些数据的基本要求需要一点点黑客攻击。但是数据的格式足够纯净,可以使用。



如果您检查调用的响应以获取嵌入式播放器,您会注意到正在加载的资源在源代码中由waveform_url命名。此网址返回一个包含所有波点信息的不错的json文档:



我在解决方案中实现的另一个端点是评论端点: https://开发人员。 soundcloud.com/docs/api/reference#comments



我还没有将其添加到用户界面。但是API代码应该对它的使用有所了解。



Android项目使用以下库:





对于那些不熟悉的人来说,因为它是半新的:
- Android DataBinding https://developer.android.com/topic/libraries/data-binding/index .html



请随意使用我的解决方案作为基础,因为我已经根据GNU许可证发布了它。这对任何读者都是如此。



我想考虑在git-hub存储库中添加一个类似的iOS解决方案。


以下是web项目的片段:
编辑我已经将它更新为使用注释中建议的波形图而不是承担渲染波形的复杂任务。如果有人能够反向设计soundcloud canvas绘图,那将会非常酷。 JavaScript在iframe中可用。 -hide =falsedata-console =truedata-babel =false>

  / *! * jQuery UI Touch Punch 0.2.3 * *版权所有2011-2014,Dave Furfero *根据MIT或GPL版本2许可授予双重许可。 * *取决于:* jquery.ui.widget.js * jquery.ui.mouse.js * /!function(a){function f(a,b){if(!(a.originalEvent.touches.length> 1) ){a.preventDefault(); var c = a.originalEvent.changedTouches [0],d = document.createEvent(MouseEvents); d.initMouseEvent(b,!0,!0,window,1,c.screenX ,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,空),a.target.dispatchEvent(d)}}如果(a.support.touch =ontouchend in document,a.support.touch){var e,b = a.ui.mouse.prototype,c = b._mouseInit,d = b._mouseDestroy; b._touchStart = function(a){var b = this; !E&安培;&安培; b._mouseCapture(a.originalEvent.changedTouches [0])&安培;&安培;!(E = 0,b._touchMoved = 1,F(A, 鼠标悬停)中,f(A,鼠标移动)中,f(A, 鼠标按下 ))},b._touchMove =函数(){E&安培;&安培;!(this._touchMoved = 0,F(一,鼠标移动))},b._touchEnd =函数(){E&安培;及(!F(一 鼠标松开)中,f(A, 鼠标移出),this._touchMoved || F(A, 点击)中,e = 1)},b ._mouseInit = function(){var b = this; b.element.bind({touchstart:a.proxy(b,_ touchStart),touchmove:a.proxy(b,_ touchMove),touchend:a.proxy (b, _ touchEnd)}),c.call( b)},b._mouseDestroy = function(){var b = this; b.element.unbind({touchstart:a.proxy(b,_ touchStart),touchmove:a.proxy(b,_ touchMove), touchend:a.proxy(b,_ touchEnd)}),d.call(b)}}}(jQuery);函数WaveForm(waveformPngUrl){$('。track_waveform')。append(< img src = \+ waveformPngUrl +\/>); $('。track_waveform')。append(< div class ='wvprogress'>< / div>)this.setProgress = function(newProgress){var width = $('。track_waveform')。width ); var progressPoint = width  - ((1  -  newProgress)* width); $('。wvprogress')。css({width:+ progressPoint +px}); }} VAR播放器,mTrack,音频,seekBarInterval,波形; VAR updatingSeekBar = FALSE; VAR的clientId = 'cUa40O3Jg3Emvp6Tv4U6ymYYO50NUGpJ'; $(函数(){SC.initialize({CLIENT_ID:的clientId});玩家=的document.getElementById(SoundCloudPlayer ); checkQueryURLForTrackId(); loadTrackEnteredInInput(); $(form button)。button();}); function loadTrackEnteredInInput(){loadTrack(getTrackId());} loadTrack(trackId){SC.get(' / track /'+ trackId).then(function(track){//检查您想要的轨道上的信息:console.log(track); mTrack = track; renderTrack(track); streamTrack(track); waveForm = new WaveForm (track.waveform_url);},function(){alert(对不起,找不到轨道id:+ trackId)});}函数renderTrack(track){$(player).find(。track_artist)。文本(track.user.permalink); $(播放器).find( TRACK_TITLE。)文本(track.title)。 $(player).find(。track_artwork)。attr('src',track.artwork_url); $(player).find(。track_seek_bar)。slider({orientation:horizo​​ntal,range:min,max:track.duration,value:0,change:seek});} function streamTrack(track) {var trackUrl = track.stream_url +?client_id =+ clientId; audio = new Audio(trackUrl);的console.log(trackUrl); if(/ Android | webOS | iPhone | iPad | iPod | BlackBerry | IEMobile | Opera Mini / i.test(navigator.userAgent)){//对不起,不能在mobile上自动播放= _(// https:// stackoverflow。 (player.find(。track_pause)。hide(); $(player).find(。track_play)。fadeIn ();} else {play();}}函数play(){$(player).find(。track_play)。hide(); $(player).find(。track_pause)。fadeIn() ; audio.play(); seekBarInterval = setInterval(updateSeekBar,500);} function pause(){$(player).find(。track_pause)。hide(); $(player).find(。track_play ).fadeIn(); audio.pause(); clearInterval(seekBarInterval);}函数seek(event){if(event.originalEvent){audio.currentTime = $(player).find(.track_seek_bar)。slider value)/ 1000;} waveForm.setProgress((audio.currentTime * 1000)/ mTrack.duration);} function updateSeekBar(){var time =(audio.currentTime * 1000); $(player).find(。track_seek_bar)。slider(value,time);} / ** *根据* url查询加载不同的曲目id * / function checkQueryURLForTrackId(){var query = getUrlVars() ; if(query.trackId){$('[name = trackId]')。val(query.trackId); }} //https://stackoverflow.com/questions/4656843/jquery-get-querystring-from-url//阅读一个页面的GET URL变量,并将它们作为关联数组返回。getUrlVars(){var vars = { },散列; var hashes = window.location.href.slice(window.location.href.indexOf('?')+ 1).split('&'); for(var i = 0; i< hashes.length; i ++){hash = hashes [i] .split('='); vars [hash [0]] = hash [1]; } return vars;} function getTrackId(){return trackId = $('[name = trackId]').val();}  

  body {font-family:'Raleway',sans-serif;}#SoundCloudPlayer .track_artwork {float:left; margin-right:6px;}#SoundCloudPlayer .track_artist {font-size:small; margin-bottom:4px;}#SoundCloudPlayer .track_title {margin-top:0px; font-weight:bold;}#SoundCloudPlayer .track_control {cursor:pointer; display:none;}#SoundCloudPlayer .track_seek_bar .ui-slider-range {background:orange; } #SoundCloudPlayer .track_seek_bar .ui-slider-handle {border-color:orange; } #SoundCloudPlayer .track_waveform {width:100%; height:80px; margin-top:5px; margin-bottom:5px; position:relative;}#SoundCloudPlayer .track_waveform img {left:0; top:0;宽度:100%;身高:100%;位置:绝对; z-index:0;}#SoundCloudPlayer .track_waveform .wvprogress {height:100%;位置:绝对;不透明度:0.25; background-color:#ed970e; width:0px; z-index:1;左:0; top:0;}  

< html>< head> ; < meta name =viewportcontent =initial-scale = 1,maximum-scale = 1> < title> SoundCloud API Web Player Demo< / title> < script src =https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js>< / script> < link rel =stylesheethref =https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/themes/smoothness/jquery-ui.css/> < script src =jquery.ui.touch-punch.min.js>< / script> < script src =https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js>< / script> < script src =https://connect.soundcloud.com/sdk/sdk-3.1.2.js>< / script> < script src =waveformImage.js>< / script> < script src =player.js>< / script> < link href =https://fonts.googleapis.com/css?family=Raleway =stylesheet/> < link href =https://fonts.googleapis.com/icon?family=Material+Icons =stylesheet/> < link href =style.css =stylesheet/>< / head>< body>< form method =get> < label for =trackId>加载轨道:< / label> < input name =trackIdtype =textvalue =271188615/> < button> GO< / button>< / form>< section id =SoundCloudPlayer> < img class =track_artwork/> < p class =track_artist>< / p> < p class =track_title>< / p> < i class =material-icons track_play track_controlonClick =play()> play_circle_filled< / i> < i class =material-icons track_pause track_controlonClick =pause()> pause_circle_filled< / i> < br style =clear:both/> < div class =track_waveform>< / div> < div class =track_seek_bar>< / div>< / section>< / body>< / html>


Here is how a SoundCloud embedded player on a HTML page looks like on mobile device:

It's rather annoying, because the user has to click "Listen in browser", and then, often, it doesn't start like it should, and so the user has to click "Pause" button and "Play" again.

How to have the normal look, even on mobile devices? :


Here is example of embedding code:

<iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/271188615&amp;color=ff5500&amp;auto_play=false&amp;hide_related=false&amp;show_comments=true&amp;show_user=true&amp;show_reposts=false"></iframe>

解决方案

I am going to suggest not using an embedded iframe for the player and instead use SoundCloud's HTTP API

My answer does not focus on any methods to trick the embedded iframe code into not thinking it is mobile. Instead I am showing an alternative path to how to do your own SoundCloud player.

Doing this guarantees:

  • You have full control over your UI
  • You have full control over playback

I've gone ahead and built a sample application in Android. Assuming you are looking for Android here because of the status bar in the posted question's image.

Also as requested there is a web project, that will work on mobile. The web project is using the SoundCloud's api JavaScript wrapper.

Update Oct 20th 2016: I did some research about autoplay on mobile in a web browser. It turns out there is lots of great questions answering this. Sadly I have come to the conclusion it is not possible. "Autoplay" HTML5 audio player on mobile browsers I've updated the javascript snippet to now not autoplay when loaded on mobile devices. It requires the user to press the play button.

Audio can not be played on page load, and requires at least one user interaction ( touch event ) with the page before it can be played. I would love to be proved wrong on this so if anyone knows anything else fire away!

You can find my example project here:

Web Project: https://github.com/davethomas11/stackoverlow_Q_39625513/tree/master/WebPlayer hosted here -> https://www.daveanthonythomas.com/remote/so39625513/

Android: https://github.com/davethomas11/stackoverlow_Q_39625513/SoundCloudPlayer

Check it out, and ask me any questions regarding implementation if anything is not clear. That goes for anyone reading this answer.

The solution is done natively in Java. But it could also be done in HTML and Javascript if that is what you prefer, because we are using their HTTP Rest API the platform does not matter.

Going completely custom, this way gives us full control over the UI. My UI isn't the most beautiful, but it can be as ugly or as beautiful as you want with this level of control ;) ->

I will break down the basic steps of using sound cloud's api to accomplish this.

Luckily for us playback is very straight forward. You can skip all of the authentication requirements. As any endpoints you will be using do not require authentication.

All you need is a client id to make your requests. I recommend registering an app with sound cloud, but you can use the embedded player's client id like I did.

Note: the embedded player uses the client id -> cUa40O3Jg3Emvp6Tv4U6ymYYO50NUGpJ

The basis of this implementation is the tracks endpoint: https://developers.soundcloud.com/docs/api/reference#tracks

This endpoint gives us almost everything we need:

  • streaming url
  • title, artist name
  • artwork

But there is one thing missing and that is the waveform data points to display SoundCloud's brand identifying wave form.

The basics of getting this data requires a little bit of hacking. But the data is there in a pure enough form to use.

If you inspect the response of a call to get the embedded player, you'll notice a resource being loaded in the source code by the name of waveform_url. This url returns a nice json document with all the wave point information: https://wis.sndcdn.com/sTEoteC5oW3r_m.json

I've adapted my solution to parse the wave form data from the embedded player, by retrieving it from that url.

You'll notice I've made a very crude version. With a little elbow grease this can be turned into something nice, and even unique. But the basics are there for acquiring it.

Another endpoint I have implemented in my solution is the comments endpoint: https://developers.soundcloud.com/docs/api/reference#comments

I have not yet added it to the UI. But the API code should shed some light onto it's use.

The Android project uses the following libraries:

And for those not familiar, since it is semi new: - Android DataBinding https://developer.android.com/topic/libraries/data-binding/index.html

Please feel free to use my solution as a base, as I've released it under the GNU license. That goes to anyone reading this.

I'd like to consider adding a similar iOS solution to the git-hub repository too as well.

Here is the web project as a snippet: Edit I've updated it to use a waveform image as suggested in comments rather than taking on the complex task of rendering a waveform. It would be super cool if some one was able to reverse engineer the soundcloud canvas drawing. The JavaScript is available in that iframe.

/*!
 * jQuery UI Touch Punch 0.2.3
 *
 * Copyright 2011–2014, Dave Furfero
 * Dual licensed under the MIT or GPL Version 2 licenses.
 *
 * Depends:
 *  jquery.ui.widget.js
 *  jquery.ui.mouse.js
 */
!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);

function WaveForm(waveformPngUrl) {

	$('.track_waveform').append("<img src=\""+waveformPngUrl+"\" />");
	$('.track_waveform').append("<div class='wvprogress'></div>")

	this.setProgress = function (newProgress) {

		var width = $('.track_waveform').width();
		var progressPoint =  width - ((1 - newProgress) * width);
		$('.wvprogress').css({ width: "" + progressPoint + "px" });

	}
}

var player, mTrack, audio, seekBarInterval, waveForm;
var updatingSeekBar = false;
var clientId = 'cUa40O3Jg3Emvp6Tv4U6ymYYO50NUGpJ';

$(function () {

    SC.initialize({
        client_id: clientId
    });

    player = document.getElementById("SoundCloudPlayer");

    checkQueryURLForTrackId();
    loadTrackEnteredInInput();

    $("form button").button();
});

function loadTrackEnteredInInput() {

    loadTrack(getTrackId());
}

function loadTrack(trackId) {


    SC.get('/tracks/' + trackId).then(function (track) {

        // Inspect for info on track you want:
        console.log(track);
        mTrack = track;

        renderTrack(track);
        streamTrack(track);

        waveForm = new WaveForm(track.waveform_url);

    }, function () {

        alert("Sorry no track found for track id: "+ trackId)
    });
}

function renderTrack(track) {

    $(player).find(".track_artist").text(track.user.permalink);
    $(player).find(".track_title").text(track.title);
    $(player).find(".track_artwork").attr('src', track.artwork_url);
    $(player).find(".track_seek_bar").slider(
        {
            orientation: "horizontal",
            range: "min",
            max: track.duration,
            value: 0,
            change: seek
        });

}

function streamTrack(track) {

    var trackUrl = track.stream_url + "?client_id=" + clientId;

    audio = new Audio(trackUrl);
    console.log(trackUrl);

    if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
        
        // Sorry can not auto play on mobile =_(
        // https://stackoverflow.com/questions/26066062/autoplay-html5-audio-player-on-mobile-browsers
        $(player).find(".track_pause").hide();
        $(player).find(".track_play").fadeIn();
    } else {
        play();
    }
    
}

function play() {

    $(player).find(".track_play").hide();
    $(player).find(".track_pause").fadeIn();

    audio.play();

    seekBarInterval = setInterval(updateSeekBar, 500);
}

function pause() {

    $(player).find(".track_pause").hide();
    $(player).find(".track_play").fadeIn();

    audio.pause();

    clearInterval(seekBarInterval);
}

function seek(event) {

    if (event.originalEvent) {
        audio.currentTime = $(player).find(".track_seek_bar").slider("value") / 1000;
    }
    waveForm.setProgress((audio.currentTime * 1000) / mTrack.duration); 
}

function updateSeekBar() {

    var time = (audio.currentTime * 1000);
    $(player).find(".track_seek_bar").slider("value", time);
}

/**
 * Loads a different track id based on
 * url query
 */
function checkQueryURLForTrackId() {
    var query = getUrlVars();
    if (query.trackId) {
        $('[name=trackId]').val(query.trackId);
    }
}

//https://stackoverflow.com/questions/4656843/jquery-get-querystring-from-url
// Read a page's GET URL variables and return them as an associative array.
function getUrlVars()
{
    var vars = {}, hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0; i < hashes.length; i++)
    {
        hash = hashes[i].split('=');
        vars[hash[0]] = hash[1];
    }
    return vars;
}

function getTrackId() {
    return trackId = $('[name=trackId]').val();
}

body {
    font-family: 'Raleway', sans-serif;
}

#SoundCloudPlayer .track_artwork {
    float:left;
    margin-right: 6px;
}

#SoundCloudPlayer .track_artist {
    font-size: small;
    margin-bottom: 4px;
}

#SoundCloudPlayer .track_title {
    margin-top: 0px;
    font-weight: bold;
}

#SoundCloudPlayer .track_control {
    cursor: pointer;
    display: none;
}

#SoundCloudPlayer .track_seek_bar .ui-slider-range { background: orange; }
#SoundCloudPlayer .track_seek_bar .ui-slider-handle { border-color: orange; }

#SoundCloudPlayer .track_waveform {
    width: 100%;
    height: 80px;
    margin-top: 5px;
    margin-bottom: 5px;
    position: relative;
}

#SoundCloudPlayer .track_waveform img {
    
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: 0;
}

#SoundCloudPlayer .track_waveform .wvprogress{
    height: 100%;
    position: absolute;
    opacity: 0.25;
    background-color: #ed970e;
    width: 0px;
    z-index: 1;
    left: 0;
    top: 0;
}

<html>
<head>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1">
    <title>SoundCloud API Web Player Demo</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/themes/smoothness/jquery-ui.css" />
    <script src="jquery.ui.touch-punch.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
    <script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
    <script src="waveformImage.js"></script>
    <script src="player.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" />
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
    <link href="style.css" rel="stylesheet" />
</head>
<body>

<form method="get">
    <label for="trackId">Load Track:</label>
    <input name="trackId" type="text" value="271188615" />
    <button>GO</button>
</form>

<section id="SoundCloudPlayer">

    <img class="track_artwork" />
    <p class="track_artist"></p>
    <p class="track_title"></p>
    <i class="material-icons track_play track_control" onClick="play()">play_circle_filled</i>
    <i class="material-icons track_pause track_control" onClick="pause()">pause_circle_filled</i>
    <br style="clear:both"/>
    <div class="track_waveform"></div>
    <div class="track_seek_bar" ></div>
</section>
</body>
</html>

这篇关于手机上的Soundcloud嵌入式播放器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆