I'm trying to write an extension for chrome that adds some extra functionality to Youtube. This particular problem has to do with knowing when the playback rate has been changed by the user (which can be done by clicking the settings icon, then speed).
I'm trying to do this by replacing the "playbackRate" property on the HTMLVideoElement with a getter/setter object so that I can detect when this happens.
When the user changes it, all my logic runs, however the video will no longer actually change speed.
let videoObj = document.getElementsByTagName('video')[0];
let storePlaybackRate = videoObj.playbackRate;
Object.defineProperty(videoObj,'playbackRate',{
get(){return storePlaybackRate;},
set(val){
storePlaybackRate = val;
console.log("Updated Value: ",val);
//Custom Logic that does work.
return val;
}
});
To test this just paste the code into the console on any youtube video, then change playback speed. The console.log happens, but the video no longer changes speed.
1.That this property is not already a getter/setter object that I'm overwriting. This is checked via:
Object.getOwnPropertyDescriptor(videoObj, 'playbackRate');
2.I thought maybe it was because I wasn't returning the new value in the setter, but that wasn't it.
I understand there are other ways of doing what I'm trying to do, and so if this is impossible by this method, that's fine. But I just really wanted to understand why this doesn't work. Or if I made an error.
Thanks.
You are overwriting an inherited getter/setter.
An HTMLVideoElement does not have its own getter/setter for playbackRate, but inherits one from HTMLMediaElement.prototype. Thats why Object.getOwnPropertyDescriptor(video,'playbackRate')
returns undefined
To overwrite it, you have to store the original descriptor, and call them within your own descriptor.
originalDescriptor = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'playbackRate');
Object.defineProperty(HTMLVideoElement.prototype,'playbackRate',{
set:function(value){
originalDescriptor.set.call(this,value);
console.log('value changed',value);
},
get:originalDescriptor.get
});
I've used the prototype for the video in this example, it is possible to adjust the descriptor for a specific element by replacing HTMLVideoElement.prototype
with the video element's reference.