Soundcloud 移动设备上的嵌入式播放器
Posted
技术标签:
【中文标题】Soundcloud 移动设备上的嵌入式播放器【英文标题】:Soundcloud embedded player on mobile 【发布时间】:2017-01-30 05:35:24 【问题描述】:以下是 html 页面上的 SoundCloud 嵌入式播放器在移动设备上的外观:
这很烦人,因为用户必须单击“在浏览器中收听”,然后,通常情况下,它并没有按应有的方式启动,因此用户必须再次单击“暂停”按钮和“播放”。
如何保持正常外观,即使在移动设备上也是如此?:
这是嵌入代码的示例:
<iframe scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/271188615&color=ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false"></iframe>
【问题讨论】:
设置 WebView 以显示桌面版本的网站有帮助。 *** ref. 【参考方案1】:我建议不要为播放器使用嵌入式 iframe,而是使用SoundCloud's HTTP API
我的回答并不关注任何方法来欺骗嵌入式 iframe 代码使其不认为它是移动的。相反,我展示了如何制作自己的 SoundCloud 播放器的替代方法。
这样做可以保证:
您可以完全控制您的用户界面 您可以完全控制播放我已经着手在 android 中构建了一个示例应用程序。假设由于发布的问题图像中的状态栏,您正在这里寻找 Android。
还应要求提供一个可在移动设备上运行的网络项目。该网络项目使用 SoundCloud 的 api javascript 包装器。
2016 年 10 月 20 日更新: 我在网络浏览器中对移动设备上的自动播放进行了一些研究。事实证明,有很多很好的问题可以回答这个问题。可悲的是,我得出的结论是不可能的。 "Autoplay" HTML5 audio player on mobile browsers 我已将 javascript sn-p 更新为现在在移动设备上加载时不会自动播放。它需要用户按下播放按钮。
音频无法在页面加载时播放,并且需要至少与页面进行一次用户交互(触摸事件)才能播放。我很想在这方面被证明是错误的,所以如果有人知道其他任何事情,那就开火吧!
您可以在这里找到我的示例项目:
网络项目: https://github.com/davethomas11/stackoverlow_Q_39625513/tree/master/WebPlayer 托管在这里 -> https://www.daveanthonythomas.com/remote/so39625513/
安卓: https://github.com/davethomas11/stackoverlow_Q_39625513/SoundCloudPlayer
检查一下,如果有任何不清楚的地方,可以问我有关实施的任何问题。这适用于任何阅读此答案的人。
解决方案是在 Java 中本地完成的。但如果您喜欢,也可以使用 HTML 和 Javascript 来完成,因为我们使用的是他们的 HTTP Rest API,平台无关紧要。
完全自定义,这种方式让我们可以完全控制 UI。 我的 UI 不是最漂亮的,但在这种级别的控制下,它可以随心所欲地变丑或变美 ;) ->
我将分解使用 Sound Cloud 的 api 来完成此操作的基本步骤。
幸运的是,我们的播放非常简单。您可以跳过所有身份验证要求。因为您将使用的任何端点都不需要身份验证。
您只需要一个客户端 ID 即可提出您的请求。 我建议使用 sound cloud 注册一个应用程序,但您可以像我一样使用嵌入式播放器的客户端 id。
注意:嵌入式播放器使用客户端id -> cUa40O3Jg3Emvp6Tv4U6ymYYO50NUGpJ
此实现的基础是 tracks 端点: https://developers.soundcloud.com/docs/api/reference#tracks
这个端点几乎为我们提供了我们需要的一切:
流媒体网址 标题、艺术家姓名 艺术品但是缺少一件事,那就是显示 SoundCloud 品牌识别波形的波形数据点。
获取这些数据的基础知识需要一些黑客攻击。但数据以足够纯净的形式存在。
如果您检查调用的响应以获取嵌入式播放器,您会注意到源代码中加载了名为waveform_url 的资源。这个 url 返回一个包含所有波点信息的漂亮 json 文档:https://wis.sndcdn.com/sTEoteC5oW3r_m.json
我已经调整了我的解决方案,通过从该 url 检索它来解析来自嵌入式播放器的波形数据。
你会注意到我做了一个非常粗略的版本。用一点肘部油脂,这可以变成漂亮的东西,甚至是独一无二的。但是,获得它的基础已经存在。
我在解决方案中实现的另一个端点是 cmets 端点:https://developers.soundcloud.com/docs/api/reference#comments
我还没有将它添加到 UI。但是 API 代码应该能够说明它的使用。
Android 项目使用以下库:
改造http://square.github.io/retrofit/ 毕加索http://square.github.io/picasso/ Stetho http://facebook.github.io/stetho/对于那些不熟悉的人,因为它是半新的: - 安卓数据绑定https://developer.android.com/topic/libraries/data-binding/index.html
请随意使用我的解决方案作为基础,因为我已根据 GNU 许可发布它。任何阅读本文的人都会如此。
我也想考虑在 git-hub 存储库中添加一个类似的 ios 解决方案。
这是一个作为 sn-p 的网络项目: 编辑我已将其更新为使用 cmets 中建议的波形图像,而不是承担渲染波形的复杂任务。 如果有人能够对 soundcloud 画布绘图进行逆向工程,那将是非常酷的。 JavaScript 在该 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://***.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://***.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>
【讨论】:
是的,当然没问题。在我发帖后我想这可能是这种情况。稍后我会回到那个例子:)。 添加了 Web 项目。 @Basj 惊人的答案! 我确实得到了一个模糊的波形。我的最终解决方案对我来说并不模糊?只需指定画布的宽度并允许高度自动为我消除模糊。模糊与画布元素的大小有关。搜索模糊的 HTML 画布。 如果您不需要从头开始绘制自己的波形,API 的第 1 版实际上会给您返回由 SoundCloud 创建的波形图像。像这个。 w1.sndcdn.com/gOCegnm5qXQm_m.png 只需使用 api.soundcloud.com 而不是 api-v2.soundcloud.com,waveform_url 就会返回一个图像。【参考方案2】:迷你播放器(高度=20)在台式机和移动设备上具有相似的外观和感觉。
<iframe scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/271188615&color=ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false"></iframe>
【讨论】:
能否添加一个可运行的代码 sn-p 和屏幕截图,以供将来参考@VadimGulyakin?【参考方案3】:您可以设置WebView
显示桌面版本。网站:
WebView view = new WebView(this);
view.getSettings().setUserAgentString("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36");
【讨论】:
【参考方案4】:使用 show_teaser=false 作为参数来隐藏叠加层。
【讨论】:
明确地说,这是 URL 上的参数,而不是 iframe 本身。以上是关于Soundcloud 移动设备上的嵌入式播放器的主要内容,如果未能解决你的问题,请参考以下文章
Youtube 自动播放无法在具有嵌入式 HTML5 播放器的移动设备上运行
来自 YouTube 的嵌入式 360 度视频无法在 iOS 浏览器上正确播放