From 5d288412f9c385178312c172ba309fffce58f0e2 Mon Sep 17 00:00:00 2001 From: Georgiy Date: Fri, 26 May 2023 18:58:05 +0300 Subject: [PATCH] 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. --- NUXT/components/Player/index.vue | 132 +++++++++++++++++++++++-------- 1 file changed, 97 insertions(+), 35 deletions(-) diff --git a/NUXT/components/Player/index.vue b/NUXT/components/Player/index.vue index ad2a8db..2415a46 100644 --- a/NUXT/components/Player/index.vue +++ b/NUXT/components/Player/index.vue @@ -27,7 +27,6 @@ }, }" mediagroup="vuetubecute" - autoplay width="100%" :src="vidSrc" :height="isFullscreen ? '100%' : 'auto'" @@ -418,20 +417,76 @@ export default { console.log("recommends", this.recommends); console.log("video", this.video); this.vid = this.$refs.player; + this.aud = this.$refs.audio; - // TODO: this.$store.state.player.quality, check if exists and select the closest one - - if (this.$store.state.player.preload) this.prebuffer(this.sources[0].url); - else { - this.prebuffer(this.sources[0].url); - this.sources.forEach((source) => { - if (source.mimeType.indexOf("audio") > -1) { - this.audSrc = source.url; - this.vidSrc = this.sources[0].url; - } - }); + /** + * 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 + let displayInfo = getPreferredQuality(); + let indexOfPreferredQuality = 0; + console.warn(displayInfo); + for (let i = this.sources.length; i > 0; i--) { + if (i === this.sources.length) continue; + else { + // 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) => { + if (source.mimeType.indexOf("audio") > -1) { + this.audSrc = source.url; + return; + } + }); + + // TODO: detect this.isMusic from the video or channel metadata instead of just SB segments this.$youtube.getSponsorBlock(this.video.id, (data) => { // console.warn("sbreturn", 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.$refs.player.addEventListener("loadeddata", this.loadedDataEvent); + this.aud.addEventListener("loadeddata", this.loadedAudioEvent); }, created() { screen.orientation.addEventListener("change", () => @@ -459,19 +512,28 @@ export default { this.cleanup(); }, methods: { + loadedAudioEvent() { + this.$refs.player.addEventListener("loadeddata", this.loadedDataEvent); + this.loadedDataEvent(); + }, loadedDataEvent() { - // console.log(e); - // if (vid.networkState === vid.NETWORK_LOADING) { - // // The user agent is actively trying to download data. - // } + // networkState: An integer property that represents the network state of the video. The possible values are: + // NETWORK_EMPTY (0): No source has been set or the video element's load() method has not been called. + // 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) { - // // There is not enough data to keep playing from this point - // } - if (this.vid.readyState >= 3) { + //readyState: An integer property that represents the readiness state of the video. The possible values are: + // 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. + // 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.$refs.audio.currentTime = this.vid.currentTime; - this.$refs.audio.play(); if (!this.isMusic) { this.$refs.audio.playbackRate = this.$store.state.player.speed; @@ -515,7 +577,11 @@ export default { clearTimeout(this.bufferingDetected); 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.buffered = (this.vid.buffered.end(0) / this.vid.duration) * 100; }, @@ -535,8 +601,8 @@ export default { clearTimeout(this.bufferingDetected); this.$refs.audio.currentTime = this.vid.currentTime; this.bufferingDetected = false; - this.$refs.audio.play(); } + this.$refs.audio.play(); }, cleanup() { if (this.xhr) this.xhr.abort(); @@ -558,9 +624,8 @@ export default { "load", () => { if (this.xhr.status === 200) { - var blob = this.xhr.response; console.error(this.xhr); - this.blobToDataURL(blob, (dataurl) => { + this.blobToDataURL(this.xhr.response, (dataurl) => { console.log(dataurl); this.vidSrc = dataurl; this.buffered = 100; @@ -586,13 +651,10 @@ export default { this.xhr.send(); }, - // !NOTE: (BUG) too big to process for 1080p vids over 2 minutes + blobToDataURL(blob, callback) { - var a = new FileReader(); - a.onload = function (e) { - callback(e.target.result); - }; - a.readAsDataURL(blob); + let url = URL.createObjectURL(new Blob([blob])); + callback(url); }, shortNext() { this.shortTransition = true;