Sound Cloud custom player - "id property is null" error - javascript

I'm having some issues working with the Sound Cloud custom html5 player (http://developers.soundcloud.com/docs/custom-player) specifically on internet explorer (tested on version 7, 8 and 9).
It seems whenever the player is created (right now this is dynamically through JS) it is running into an error with a function in the "sc-player.js" file (provided by sound cloud here).
The error is "Unable to get the value or property 'id': object null or undefined". This is the code that messes up: line 640 character 9
// selecting tracks in the playlist
$('.sc-trackslist li').live('click', function(event) {
var $track = $(this),
$player = $track.closest('.sc-player'),
trackId = $track.data('sc-track').id,
play = $player.is(':not(.playing)') || $track.is(':not(.active)');
if (play) {
onPlay($player, trackId);
}else{
onPause($player);
}
$track.addClass('active').siblings('li').removeClass('active');
$('.artworks li', $player).each(function(index) {
$(this).toggleClass('active', index === trackId);
});
return false;
});
I understand this is trying to find the id of a track on the generated list, however I have hidden this list on the page, so really shouldn't that click event should not even fire? I have tried removing the click event all together but that seems to cause a number of other issues with the player.
Just wondering if anyone else has experienced this or knows how to get around it?
EDIT -
I manually attached "test" data the track. And this seems to solve that first error, but of course brings up another. This time the same error is spat out for this line (in the sc-player.js file):
getPlayerData = function(node) {
return players[$(node).data('sc-player').id];
}
This is the code I use to call the player, the track argument being the link to a music tracks soundcloud page, and #player being the empty div its being created on top of:
function init_player(track,title) {
$('.open #player').scPlayer({
links: [{url: track, title: title}],
beforeRender : function(tracksData) {
$scplayer = $(this);
$('.sc-trackslist li, .sc-trackslist li a').data({ id: track});
}
}
When the user wants to change to another section of music, I then have another function which empties the container div, appends #player to it (because it was overwritten by the soundcloud player), and re runs the above function.
My issue is on the second time the init_player function is run, I get the error.
Sorry for the delayed response!

This line is wrong:
trackId = $track.data('sc-track').id,
I can't help you more then that because I need the rest of the code...

Related

YouTube IFrame Player doesn't execute cuePlayList correctly

I have a website where I create a YouTube player in an IFrame and make it grab different playlists depending on what the user clicks. So it calls player.cuePlaylist({listType:"playlist",list:playListID})
where playListIDis the variable that changes when the user calls for different playlists. The problem is the first time the function gets executed it works fine, but as soon as it's asked a second time to cue a new playList, it doesn't do anything, no 400 error message or anything either, but when I call the second playList a second time, it works.
This cuePlayList function seems to be bugged as this did not occur a month or two ago. The only change I can see to the youtube Iframe API is about search lists, not playlists as you can read here
I recreated the bug in this jsfiddle. Just press the "new playlist" button and it will load the correct playlist, press another playlist and it won't do anything until pressed twice.
So am I doing something wrong or is this on YouTube's IFrame API end?
Thanks in advance!
Instead of destroying the player, meaning you can't use cuePlaylist() and loadPlaylist() anymore, I found out the player accepts the new playlist if you call the cue/load function twice like so: https://jsfiddle.net/5yw2na96/
I found out about this issue by linking the cuePlaylist() function to a button and noticing you need to click twice for the playlist to update correctly. There seems to be a delay needed between the empty call and the actual call so I set it to 500ms.
I implemented a workaround by destroying the player and initializing a new one with the playlist I'd like to load.
embed.destroy();
embed = new YT.Player('video-placeholder', {
width: 600,
height: 400,
playerVars:
{
listType: 'playlist',
list: playlistId,
index: 0
},
events: {
'onReady': function (event) {
player = event.target;
}
}
});
The method described above, chaining an empty call and the actual cue function after a certain amount of milliseconds, appears to not be working anymore if you also have to specify a specific index to start from. The new playlist is correctly loaded but the index is set back to 0 no matter where in the playlist you were when the update happened.
There's nothing much to change from the method above to fix the issue: you can simply assign a callback function to a variable and chain that instead. Example: https://jsfiddle.net/o0f815t3/
const cIndex = player.getPlaylistIndex(),
cTime = player.getCurrentTime(),
callback = function() { player.cuePlaylist(myPlaylist, cIndex, cTime) };
callback();
setTimeout(() => { callback() }, 500)

How to change a loaded video source from other html file?

Basically I've an html file which contains all the elements needed for my web app videos.
So Now I'm in a position where I need to counts numbers of user videos and show them to user.
Script:
for(var i=1;i<(s.length)-2;i++){
$('#vid_c_'+i).append('<div id="vid_'+i+'"></div>');
$("<div>").load("video_content.html",function(index) {
return function() {
$(this).find('.video').attr({id: 'video_id_'+index});
$("#vid_"+index).append($(this).html());
}
})(i));
var myElem = document.getElementById('video_id_'+i);
if (myElem === null) alert('does not exist!');
$(this).find('#video_id_'+i).attr('src', video_src[i-1]);
console.log(video_src[i-1]+ " "+"#video_id_"+i);
}
So Basically What happen is that for loop creates (s.length)-2 which is the amount of user videos and load video elements in a div and for each video it specifies a unique ID increased by value of i. So far it works fine now I need to specify video source which is assigned in video_src[i-1].
As you can see I've myElem which test if the element exists or not And the result is the it alerts saying does not exist even though I have loaded my video element And I can see it in my browser inspect mode with the Id assigned fine which makes the next line for assigning video source not to work. I also have tried:
$(this).find('.video').attr({id: 'video_id_'+index, 'src': video_src[i-1]});
and inside .load() function video_src shows to be undefined.
In my console.log it show the exact video source as needs to be assigned.
So I would really appreciate if someone tell me how to assign video source each time the video element is loaded from my video_content.html file.
Anyway, Based on all my research And tests I had I came up that inside .load(function(){}); I can't access data of current page because it's executing script from my video_cntent.html file. So In order to set the source of my video element I created two for Loops:
for(var i=1;i<(s.length)-2;i++){
var video_src = video_source[i-1];
localStorage.setItem('Item_'+i, video_src);
$('#vid_c_'+i).append('<div class="move_2" id="vidi_'+i+'"></div>');
}
for(var i=1;i<(s.length)-2;i++){
$("<div>").load("video_cntent.html",(function(index) {
return function() {
var retrieveitem = localStorage.getItem('Item_'+index);
$(this).find('#vidi_'+index).attr({id: 'video_id_'+index, 'src': retrieveitem});
}
})(i));
}
As you can see in my first loop I am accessing video_source and storing it in localStorage and it stores all my video sources based on value of i.
And in my second Loop I'm retrieving all the stored data again based on value of i and using it to set source of my video element.

Volume for sound not consistent when calling string from localStorage

I have a function that is behaving in a way that i do not like, and i cannot identify why. The overall function works fine, and when the volume is changed using the range element somewhere else in the interface, that works too. But lets say if I set the object in localStorage to "0.6" it will play at the right volume, BUT every so often it behaves as if the volume is "1" or default(i think). I sent the variable to my console to see what it says and it behaves like there is nothing wrong. The audio still sometimes gives me default volume even though the console says it's the right number stored in LS.
Here is the JS to the function that fires my biting sound:
biteFunc: function () {
var snd, myAu;
myAu = localStorage.getItem("Au");
//the user uses a range input to set this value, works fine
snd = new Audio("../Audio/bite.wav");
//the file in the location i want it to be, works fine
if (!myAu || myAu === "0") {
return false;
//if the user sets the sound to "0", the function will not fire
}
if (myAu) {
snd.volume = myAu;
snd.play();
/*this works and the console shows that each time the sound is fired,
the correct volume is there. But sometimes(especially when tapping
the button quickly) the volume behaves like its default or "1"
even though the object console says the right volume
*/
}
}
-Could my function be firing without reading the volume and spitting out the default volume when that happens?
-I thought it to be a timeline issue so I set the volume inside of the conditional that detects myAu, still nothing.

jwplayer 6 seeking on element in playlist doesn't work

We're using an external scrubber (a UI element that is not the default seek bar) for seeking (via jquery ui draggable) and it is not updating the jwplayer when it should be.
Synopsis of our code:
$('#scrubber').draggable({
// ...
stop: function (event, ui) {
$('#scrubber').draggable('enable');
var intSecFromEnd,
intSeek,
intTotalTime = 0,
intScrubPosition = ui.position.left,
intScrubTime = intScrubPosition;
// Find which video in the playlist to use
$.each(playlist, function (i, obj) {
intTotalTime += parseInt(obj.duration);
if (intTotalTime > (intScrubTime)) {
intSecFromEnd = intTotalTime - parseInt(intScrubTime);
intSeek = Math.floor((parseInt(obj.duration) - intSecFromEnd));
jwplayer('videoPlayer').load(playlist);
jwplayer('videoPlayer').playlistItem(i);
jwplayer('videoPlayer').seek(intSeek);
jwplayer('videoPlayer').pause();
/*
Play the video for 1 second to refresh the video player, so it is correctly displaying the current point in the video
Does not work either
*/
// setTimeout(function () {
// jwplayer('videoPlayer').pause();
// }, 1000);
return false;
}
});
}
});
You'll notice the key bit:
jwplayer('videoPlayer').load(playlist);
jwplayer('videoPlayer').playlistItem(i);
jwplayer('videoPlayer').seek(intSeek);
jwplayer('videoPlayer').pause();
When i put this into the console directly with an integer value where intSeek is it works exactly as it should, so I'm puzzled where the disconnect might be.
variation (that only works one one item in the playlist)
This works on the first member of the playlist only because the seek() function is defaulted to element 0 in the playlist.
jwplayer('videoPlayer').load(playlist);
jwplayer('videoPlayer').seek(intSeek);
jwplayer('videoPlayer').pause();
Naturally, it would stand to reason that jwplayer('videoPlayer').playlistItem(i) would retrieve the item at the index we want and, according to the docs, should:
Start playback of the playlist item at the specified index.
but, as this is effectively what is in the first example, it doesn't work.
Notes
When triggering the .seek() method externally from the player, the onSeek() method never gets fired by the jwplayer.
putting in the following, the jwplayer onReady event never gets fired. jwplayer(strVideo).playlistItem(i).onReady({ console.log('ready'); });
we're trying onPlaylistItem(index).seek(seconds) but this doesn't works.
This work only on active playlistitem and -of course- only about first file.
We're trying to use a pre-loaded playlist with seek button for every item of playlist.
We use a playlist with more files and the user can go to a specific file and second clicking a button that call:
jwplayer().onPlaylistItem(<index_file>).seek(seconds);
This jump to the seconds but not to the correct playlist item.
With a previuos test using "playListItem" player jump to the correct file but start from beginning and not seek to seconds. (but work only in html5 mode and not with flash).
Now we've tested this code
<a onclick='var only_once =false;jwplayer().playlistItem(1);jwplayer().onPlay(function () {
if (only_once == false) {
only_once = true;
jwplayer().seek(60);
}
});' class="btn">HLS play 2nd file at 1 min</a>
but this solution works only in Flash mode and not in html 5 mode player!

JS .play() on iPad plays wrong file...suggestions?

So, I am building a web app that has a div with text that changes on various user actions (it's stepping through an array of pieces of text). I'm trying to add audio to it, so I made another array with the sound files in the appropriate positions:
var phrases=['Please hand me the awl.','etc1','etc2','etc3'];
var phrasesAudio=['awl.mp3','etc1.mp3','etc2.mp3','etc3.mp3'];
And on each action completion, a 'counter' variable in incremented, and each array looks for the object at that counter
var audio = document.createElement("audio"),
canPlayMP3 = (typeof audio.canPlayType === "function" &&
audio.canPlayType("audio/mpeg") !== "");
function onAction(){
correct++;
document.getElementById('speech').innerHTML=phrases[correct];
if(canPlayMP3){
snd = new Audio(phrasesAudio[correct]);
}
else{
snd = new Audio(phrasesAudioOgg[correct]);
}
snd.play();
}
(the text replaces a div's HTML and I use .play() for the audio object)...usually works okay (and ALWAYS does in a 'real' browser), but on the iPad (the actual target device) after a few successful iterations, the TEXT continues to progress accurately, but the AUDIO will hiccup and repeat a sound file one or more times. I added some logging and looking there it reports that it's playing screw.mp3 (just an example, no particular file is more or less error prone), but in actuality it plays screwdriver.mp3 (the prior file, if there is an error, the audio always LAGS, never LEADS)...because of this I am thinking that the problem is with my use of .play()...so I tried setting snd=null; between each sound, but nothing changed...Any suggestions for how to proceed? This is my first use of audio elements so any advice is appreciated. Thanks.
edit: I've also tried setting the files with snd.src (based on https://wiki.mozilla.org/Audio_Data_API) and this caused no audio to play
for iPad you need to call snd.load() before snd.play() - otherwise you get "odd" behaviour...
see for some insight:
http://jnjnjn.com/187/playing-audio-on-the-ipad-with-html5-and-javascript/
Autoplay audio files on an iPad with HTML5
EDIT - as per comment from the OP:
Here https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox you can find a tip on halting a currently playing piece of media with
var mediaElement = document.getElementById("myMediaElementID");
mediaElement.pause();
mediaElement.src = "";
and, following that with setting the correct src, load(), play() works great

Categories

Resources