0
0
Fork 0
mirror of https://github.com/VueTubeApp/VueTube synced 2024-11-25 04:35:17 +00:00

refactor(videoPlaying): Removed autoplay parameter in video element, Added auto-selection of the maximum supported quality for the device depending on its resolution (DOES NOT depend on Internet speed). Updated, but temporary disabled blobToDataURL function (cause bugs, such as repeating video when url in video element changes, quality selector breaking etc.).

Maybe fixed out of sync audio and video, and possibly incorrect loading of video and audio.
This commit is contained in:
Georgiy 2023-05-26 18:58:05 +03:00
parent 6d9fcda349
commit 5d288412f9

View file

@ -27,7 +27,6 @@
}, },
}" }"
mediagroup="vuetubecute" mediagroup="vuetubecute"
autoplay
width="100%" width="100%"
:src="vidSrc" :src="vidSrc"
:height="isFullscreen ? '100%' : 'auto'" :height="isFullscreen ? '100%' : 'auto'"
@ -418,20 +417,76 @@ export default {
console.log("recommends", this.recommends); console.log("recommends", this.recommends);
console.log("video", this.video); console.log("video", this.video);
this.vid = this.$refs.player; this.vid = this.$refs.player;
this.aud = this.$refs.audio;
/**
* Video quality selection which device can play normally
* @returns {number[]}
*/
function getPreferredQuality() {
let width;
let height;
// Detecting device - https://stackoverflow.com/a/11381730/18543384
window.mobileCheck = function () {
let check = false;
(function (a) {
if (
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
a
) ||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
a.substr(0, 4)
)
)
check = true;
})(navigator.userAgent || navigator.vendor || window.opera);
return check;
};
// The smartphone screen width is smaller than the length (1080x1920).
// On a computer, the opposite is true (1920x1080).
// Detecting smaller side of the display.
if (window.mobileCheck) {
width = window.screen.width * window.devicePixelRatio;
height = window.screen.height * window.devicePixelRatio;
} else {
width = window.screen.height * window.devicePixelRatio;
height = window.screen.width * window.devicePixelRatio;
}
return [width, height];
}
// TODO: this.$store.state.player.quality, check if exists and select the closest one // TODO: this.$store.state.player.quality, check if exists and select the closest one
let displayInfo = getPreferredQuality();
if (this.$store.state.player.preload) this.prebuffer(this.sources[0].url); let indexOfPreferredQuality = 0;
console.warn(displayInfo);
for (let i = this.sources.length; i > 0; i--) {
if (i === this.sources.length) continue;
else { else {
this.prebuffer(this.sources[0].url); // if quality height <= to the smaller side of the display,
// write the index of the source to a variable indexOfPreferredQuality.
if (
this.sources[i].height <= displayInfo[1] &&
this.sources[i].mimeType.includes("video")
) {
indexOfPreferredQuality = i;
}
if (this.sources[i].mimeType.indexOf("audio") > -1) {
this.audSrc = this.sources[i].url;
}
}
}
this.vidSrc = this.sources[indexOfPreferredQuality].url;
// this.prebuffer(this.sources[indexOfPreferredQuality].url);
this.sources.forEach((source) => { this.sources.forEach((source) => {
if (source.mimeType.indexOf("audio") > -1) { if (source.mimeType.indexOf("audio") > -1) {
this.audSrc = source.url; this.audSrc = source.url;
this.vidSrc = this.sources[0].url; return;
} }
}); });
}
// TODO: detect this.isMusic from the video or channel metadata instead of just SB segments
this.$youtube.getSponsorBlock(this.video.id, (data) => { this.$youtube.getSponsorBlock(this.video.id, (data) => {
// console.warn("sbreturn", data); // console.warn("sbreturn", data);
if (Array.isArray(data)) { if (Array.isArray(data)) {
@ -446,9 +501,7 @@ export default {
} }
}); });
// TODO: detect this.isMusic from the video or channel metadata instead of just SB segments this.aud.addEventListener("loadeddata", this.loadedAudioEvent);
this.$refs.player.addEventListener("loadeddata", this.loadedDataEvent);
}, },
created() { created() {
screen.orientation.addEventListener("change", () => screen.orientation.addEventListener("change", () =>
@ -459,19 +512,28 @@ export default {
this.cleanup(); this.cleanup();
}, },
methods: { methods: {
loadedAudioEvent() {
this.$refs.player.addEventListener("loadeddata", this.loadedDataEvent);
this.loadedDataEvent();
},
loadedDataEvent() { loadedDataEvent() {
// console.log(e); // networkState: An integer property that represents the network state of the video. The possible values are:
// if (vid.networkState === vid.NETWORK_LOADING) { // NETWORK_EMPTY (0): No source has been set or the video element's load() method has not been called.
// // The user agent is actively trying to download data. // NETWORK_IDLE (1): The video element's load() method has been called, and the video is fetching the media resource.
// } // NETWORK_LOADING (2): The video is in the process of downloading the media resource.
// NETWORK_NO_SOURCE (3): No suitable source found for the video.
// if (vid.readyState < vid.HAVE_FUTURE_DATA) { //readyState: An integer property that represents the readiness state of the video. The possible values are:
// // There is not enough data to keep playing from this point // HAVE_NOTHING (0): No information about the media resource is available.
// } // HAVE_METADATA (1): Basic metadata about the media resource, such as duration, is available.
if (this.vid.readyState >= 3) { // HAVE_CURRENT_DATA (2): Data for the current playback position is available but not enough to start playback.
// HAVE_FUTURE_DATA (3): Data for the current and at least the next frame is available.
// HAVE_ENOUGH_DATA (4): Enough data is available to start playback.
if (this.vid.readyState >= 3 && this.aud.readyState >= 3) {
this.vid.play();
this.aud.play();
this.bufferingDetected = false; this.bufferingDetected = false;
this.$refs.audio.currentTime = this.vid.currentTime;
this.$refs.audio.play();
if (!this.isMusic) { if (!this.isMusic) {
this.$refs.audio.playbackRate = this.$store.state.player.speed; this.$refs.audio.playbackRate = this.$store.state.player.speed;
@ -515,7 +577,11 @@ export default {
clearTimeout(this.bufferingDetected); clearTimeout(this.bufferingDetected);
this.bufferingDetected = false; this.bufferingDetected = false;
} }
if (this.$refs.audio.paused && !this.$refs.player.paused) if (
this.$refs.audio.paused &&
!this.$refs.player.paused &&
this.$refs.player.readyState >= 3
)
this.$refs.audio.play(); this.$refs.audio.play();
this.buffered = (this.vid.buffered.end(0) / this.vid.duration) * 100; this.buffered = (this.vid.buffered.end(0) / this.vid.duration) * 100;
}, },
@ -535,8 +601,8 @@ export default {
clearTimeout(this.bufferingDetected); clearTimeout(this.bufferingDetected);
this.$refs.audio.currentTime = this.vid.currentTime; this.$refs.audio.currentTime = this.vid.currentTime;
this.bufferingDetected = false; this.bufferingDetected = false;
this.$refs.audio.play();
} }
this.$refs.audio.play();
}, },
cleanup() { cleanup() {
if (this.xhr) this.xhr.abort(); if (this.xhr) this.xhr.abort();
@ -558,9 +624,8 @@ export default {
"load", "load",
() => { () => {
if (this.xhr.status === 200) { if (this.xhr.status === 200) {
var blob = this.xhr.response;
console.error(this.xhr); console.error(this.xhr);
this.blobToDataURL(blob, (dataurl) => { this.blobToDataURL(this.xhr.response, (dataurl) => {
console.log(dataurl); console.log(dataurl);
this.vidSrc = dataurl; this.vidSrc = dataurl;
this.buffered = 100; this.buffered = 100;
@ -586,13 +651,10 @@ export default {
this.xhr.send(); this.xhr.send();
}, },
// !NOTE: (BUG) too big to process for 1080p vids over 2 minutes
blobToDataURL(blob, callback) { blobToDataURL(blob, callback) {
var a = new FileReader(); let url = URL.createObjectURL(new Blob([blob]));
a.onload = function (e) { callback(url);
callback(e.target.result);
};
a.readAsDataURL(blob);
}, },
shortNext() { shortNext() {
this.shortTransition = true; this.shortTransition = true;