0
0
Fork 0
mirror of https://github.com/VueTubeApp/VueTube synced 2024-11-29 06:33:05 +00:00

player settings: preload

This commit is contained in:
Nikita Krupin 2022-07-29 00:44:26 -04:00
parent 51b0be2acd
commit c598603450
6 changed files with 180 additions and 73 deletions

View file

@ -33,8 +33,12 @@
:height="isFullscreen ? '100%' : 'auto'" :height="isFullscreen ? '100%' : 'auto'"
style="transition: filter 0.15s ease-in-out, transform 0.15s linear" style="transition: filter 0.15s ease-in-out, transform 0.15s linear"
:class=" :class="
controls || seeking || skipping controls ||
? verticalFullscreen seeking ||
skipping ||
($store.state.player.preload && buffered < 100)
? verticalFullscreen &&
!($store.state.player.preload && buffered < 100)
? 'dim-ish' ? 'dim-ish'
: 'dim' : 'dim'
: '' : ''
@ -137,6 +141,7 @@
<!-- controls container --> <!-- controls container -->
<div <div
v-if="$refs.player && $refs.player.currentSrc"
style="transition: opacity 0.15s ease-in-out" style="transition: opacity 0.15s ease-in-out"
:style=" :style="
controls && !seeking controls && !seeking
@ -248,7 +253,7 @@
<v-spacer /> <v-spacer />
<!-- // TODO: merge the bottom 2 into 1 reusable component --> <!-- // TODO: merge the bottom 2 into 1 reusable component -->
<quality <quality
v-if="$refs.player" v-if="$refs.player && $refs.player.currentSrc"
:sources="sources" :sources="sources"
:current-source="$refs.player" :current-source="$refs.player"
@quality="qualityHandler($event)" @quality="qualityHandler($event)"
@ -309,6 +314,22 @@
($refs.player.currentTime = $event), ($refs.audio.currentTime = $event) ($refs.player.currentTime = $event), ($refs.audio.currentTime = $event)
" "
/> />
<v-progress-circular
v-if="$store.state.player.preload && buffered < 100"
style="
transform: translate(-50%, -50%);
position: absolute;
left: 50%;
top: 50%;
"
:value="buffered"
color="primary"
:rotate="-90"
:size="64"
>
<b>{{ buffered }}%</b>
</v-progress-circular>
</div> </div>
</template> </template>
@ -381,7 +402,7 @@ export default {
let vid = this.$refs.player; let vid = this.$refs.player;
// 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
if (this.$store.state.player.prebuffer) this.prebuffer(this.sources[0].url); if (this.$store.state.player.preload) this.prebuffer(this.sources[0].url);
else { else {
this.audSrc = this.sources[this.sources.length - 1].url; this.audSrc = this.sources[this.sources.length - 1].url;
this.vidSrc = this.sources[0].url; this.vidSrc = this.sources[0].url;
@ -439,26 +460,29 @@ export default {
); );
}, },
beforeDestroy() { beforeDestroy() {
this.xhr.abort();
if (this.isFullscreen) this.exitFullscreen(); if (this.isFullscreen) this.exitFullscreen();
screen.orientation.removeEventListener("change"); screen.orientation.removeEventListener("change");
}, },
methods: { methods: {
prebuffer(url) { prebuffer(url) {
var xhr = new XMLHttpRequest(); this.xhr = new XMLHttpRequest();
xhr.open("GET", url, true); this.xhr.open("GET", url, true);
xhr.responseType = "blob"; this.xhr.responseType = "blob";
xhr.addEventListener( this.xhr.addEventListener(
"load", "load",
() => { () => {
if (xhr.status === 200) { if (this.xhr.status === 200) {
var blob = xhr.response; var blob = this.xhr.response;
console.error(this.xhr);
this.blobToDataURL(blob, (dataurl) => { this.blobToDataURL(blob, (dataurl) => {
console.log(dataurl); console.log(dataurl);
this.vidSrc = dataurl; this.vidSrc = dataurl;
this.buffered = 100;
}); });
} else { } else {
console.error("errorred pre-fetch", xhr.status); console.error("errorred pre-fetch", this.xhr.status);
} }
}, },
false false
@ -466,17 +490,18 @@ export default {
var prev_pc = 0; var prev_pc = 0;
// TODO: big progress overlay (##%) to replace controls while loading if pre-buffering is enabled // TODO: big progress overlay (##%) to replace controls while loading if pre-buffering is enabled
xhr.addEventListener("progress", (event) => { this.xhr.addEventListener("progress", (event) => {
if (event.lengthComputable) { if (event.lengthComputable) {
var pc = Math.round((event.loaded / event.total) * 100); var pc = Math.round((event.loaded / event.total) * 100);
if (pc != prev_pc) { if (pc != prev_pc) {
prev_pc = pc; // ##% prev_pc = pc; // ##%
console.log("buffering progress", pc); if (pc < 100) this.buffered = pc;
console.warn(this.xhr);
} }
} }
}); });
xhr.send(); this.xhr.send();
}, },
blobToDataURL(blob, callback) { blobToDataURL(blob, callback) {
var a = new FileReader(); var a = new FileReader();

View file

@ -6,63 +6,92 @@
<!-- // TODO: quality auto-adjustment settings --> <!-- // TODO: quality auto-adjustment settings -->
<!-- // TODO: Data saver --> <!-- // TODO: Data saver -->
<!-- // TODO: Player UI --> <!-- // TODO: Player UI -->
<!-- <v-divider v-if="!$store.state.tweaks.roundTweak" />
<v-divider v-if="!$store.state.tweaks.roundTweak" />
<h3 class="ml-8 mt-8"> <h3 class="ml-8 mt-8">
<v-icon class="mb-1 mr-1">mdi-play-speed</v-icon> <v-icon class="mb-1 mr-1">mdi-play-speed</v-icon>
Preload Preload (UNSTABLE)
</h3> </h3>
<v-card <v-card
flat flat
class="mx-4 my-2 pa-4 d-flex flex-row justify-between background" class="mx-4 mt-2 mb-8 background"
:class="
$store.state.tweaks.roundTweak > 0
? $vuetify.theme.dark
? 'lighten-1'
: 'darken-1'
: ''
"
:style="{ :style="{
borderRadius: `${$store.state.tweaks.roundTweak / 2}rem`, border: preload
? `2.1px solid var(--v-primary-base) !important`
: '2.1px solid var(--v-background-base)',
borderRadius: `${$store.state.tweaks.roundTweak / 1.9}rem`,
}" }"
@click="(preload = !preload), $vuetube.haptics.hapticsImpactLight(1)"
> >
<div> <v-card
Pre-buffer video data before playback to avoid buffering pauses. flat
<b class="red--text">(can be data intensive it high quality presets)</b> class="pa-4 d-flex flex-row background"
<br /> :class="
<br /> $store.state.tweaks.roundTweak > 0
<hr class="primary mr-6" style="opacity: 0.25" /> ? $vuetify.theme.dark
<span class="overline">Buffering threshold: 15%</span> ? 'lighten-1'
</div> : 'darken-1'
<v-spacer /> : ''
<v-switch "
v-model="preload" :style="{
style="pointer-events: none" borderRadius: `${$store.state.tweaks.roundTweak / 2}rem`,
class="mt-0" }"
inset @click="(preload = !preload), $vuetube.haptics.hapticsImpactLight(1)"
/> >
<br /> <div class="pr-4">
<div style="font-size: 0.75rem">
Pre-buffer video data before playback to avoid buffering pauses.
<b class="primary--text">
(can be data intensive at high quality presets)
</b>
</div>
<div
:class="preload ? 'primary' : 'background'"
class="my-3 mr-6 rounded-right"
style="width: 100%; height: 2px; margin-left: -1.1rem"
/>
<div>Buffering Threshold &middot; {{ preloadUpTo }}%</div>
<div
class="background--text"
:class="$vuetify.theme.dark ? 'text--lighten-4' : 'text--darken-4'"
style="font-size: 0.75rem"
>
The video will start playing after this much of the video is loaded.
<b class="red--text">(doesn't work yet)</b>
</div>
</div>
<v-switch
v-model="preload"
style="pointer-events: none"
class="mt-0"
inset
/>
</v-card>
<v-slider <v-slider
v-model="speed" v-show="preload"
step=".25" v-model="preloadUpTo"
thumb-size="64" :min="1"
style="transition-duration: 0.3s; transition-property: all" :max="100"
:rules="[(s) => s <= 4 || 'Might cause issues with buffering.']" thumb-label
:min="0.25" persistent-hint
:max="16" height="20"
:hint="preloadUpTo <= 10 || 'This can take a very long time.'"
class="pt-4 px-0 pb-1"
track-color="background"
thumb-color="primary background--text"
style="z-index: 69420; position: absolute; bottom: -1.83rem"
:style="{
borderRadius: `${$store.state.tweaks.roundTweak / 4}rem`,
width: `calc(100% - 2rem - ${$store.state.tweaks.roundTweak}rem)`,
left: `${$store.state.tweaks.roundTweak / 2 + 1}rem`,
}"
@input="$vuetube.haptics.hapticsImpactLight(0)" @input="$vuetube.haptics.hapticsImpactLight(0)"
> >
<template #thumb-label="{ value }">
<b class="background--text" style="font-size: 1.15rem">
{{ value.toFixed(2) }}x
</b>
</template>
</v-slider> </v-slider>
</v-card> --> </v-card>
<v-divider v-if="!$store.state.tweaks.roundTweak" /> <v-divider v-if="!$store.state.tweaks.roundTweak && !preload" />
<h3 class="ml-8 mt-8"> <h3 class="ml-8 mt-8">
<v-icon class="mb-1 mr-1">mdi-speedometer</v-icon> <v-icon class="mb-1 mr-1">mdi-speedometer</v-icon>
@ -79,7 +108,7 @@
> >
<v-card <v-card
flat flat
class="mb-1 pa-4 d-flex flex-row justify-between background" class="mb-1 pa-4 d-flex flex-row background"
:class=" :class="
$store.state.tweaks.roundTweak > 0 $store.state.tweaks.roundTweak > 0
? $vuetify.theme.dark ? $vuetify.theme.dark
@ -114,16 +143,9 @@
inset inset
/> />
</v-card> </v-card>
<v-card flat class="d-flex flex-row justify-between background"> <v-card flat class="d-flex flex-row background">
<speed <speed
class="background mr-1 px-4 d-flex justify-center align-center" class="background mr-1 px-4 d-flex justify-center align-center"
style="
font-size: 1.5rem !important;
font-weight: bold !important;
color: black !important;
background: red;
text-shadow: 0 0 2rem green;
"
:current-speed="speed" :current-speed="speed"
:class=" :class="
$store.state.tweaks.roundTweak > 0 $store.state.tweaks.roundTweak > 0
@ -142,7 +164,6 @@
step=".25" step=".25"
thumb-size="64" thumb-size="64"
class="pa-0 pt-5 pl-6 pb-2 ma-0 background" class="pa-0 pt-5 pl-6 pb-2 ma-0 background"
style="transition-duration: 0.3s; transition-property: all"
:rules="[(s) => s <= 4 || 'Might cause issues with buffering.']" :rules="[(s) => s <= 4 || 'Might cause issues with buffering.']"
:min="0.25" :min="0.25"
:max="16" :max="16"
@ -176,7 +197,18 @@ export default {
components: { components: {
speed, speed,
}, },
data: function () {
return this.initializeState();
},
computed: { computed: {
loop: {
get() {
return this.$store.state.player.loop;
},
set(value) {
this.$store.commit("player/setLoop", value);
},
},
speed: { speed: {
get() { get() {
return this.$store.state.player.speed; return this.$store.state.player.speed;
@ -201,6 +233,49 @@ export default {
this.$store.commit("player/setPreload", value); this.$store.commit("player/setPreload", value);
}, },
}, },
preloadUpTo: {
get() {
return this.$store.state.player.preloadUpTo;
},
set(value) {
this.$store.commit("player/setPreloadUpTo", value);
},
},
},
methods: {
initializeState() {
return {
toggles: [
{
value: false,
name: "Captions",
icon: "mdi-closed-caption",
disabled: true,
},
{
value: false,
name: "Autoskip",
icon: "mdi-skip-next",
disabled: true,
},
{
action: () => {},
value: false,
name: "Mute",
icon: "mdi-volume-off",
disabled: true,
},
{
action: () => {
this.loop = !this.loop;
},
value: this.loop,
name: "Loop",
icon: "mdi-sync-circle",
},
],
};
},
}, },
}; };
</script> </script>

View file

@ -126,7 +126,7 @@
<v-divider v-if="!$store.state.tweaks.roundTweak" /> <v-divider v-if="!$store.state.tweaks.roundTweak" />
<v-card <v-card
flat flat
class="d-flex flex-row justify-between mx-4 mb-4 pa-4 background" class="d-flex flex-row mx-4 mb-4 pa-4 background"
:class=" :class="
$store.state.tweaks.roundTweak > 0 $store.state.tweaks.roundTweak > 0
? $vuetify.theme.dark ? $vuetify.theme.dark

View file

@ -6,7 +6,7 @@
<!-- // TODO: Top and Bottom bar color selection --> <!-- // TODO: Top and Bottom bar color selection -->
<v-card <v-card
flat flat
class="mx-4 my-2 px-4 py-2 d-flex flex-row justify-between background" class="mx-4 my-2 px-4 py-2 d-flex flex-row background"
style="transition-duration: 0.3s; transition-property: border-radius" style="transition-duration: 0.3s; transition-property: border-radius"
:class=" :class="
roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : '' roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : ''
@ -35,7 +35,7 @@
<v-card <v-card
flat flat
class="mx-4 my-2 px-4 py-2 d-flex flex-row justify-between background" class="mx-4 my-2 px-4 py-2 d-flex flex-row background"
style="transition-duration: 0.3s; transition-property: border-radius" style="transition-duration: 0.3s; transition-property: border-radius"
:class=" :class="
roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : '' roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : ''
@ -79,7 +79,7 @@
<!-- margin: $store.state.tweaks.roundTweak > 0 ? '0 1rem' : '0', --> <!-- margin: $store.state.tweaks.roundTweak > 0 ? '0 1rem' : '0', -->
<v-card <v-card
flat flat
class="mb-1 px-4 py-2 d-flex flex-row justify-between background" class="mb-1 px-4 py-2 d-flex flex-row background"
:class=" :class="
roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : '' roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : ''
" "
@ -107,7 +107,7 @@
</v-card> </v-card>
<v-card <v-card
flat flat
class="mb-1 px-4 py-2 d-flex flex-row justify-between background" class="mb-1 px-4 py-2 d-flex flex-row background"
:class=" :class="
roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : '' roundTweak > 0 ? ($vuetify.theme.dark ? 'lighten-1' : 'darken-1') : ''
" "
@ -151,7 +151,7 @@
<template #thumb-label="{ value }"> <template #thumb-label="{ value }">
<div <div
class="pa-4 background" class="pa-4 background"
:style="{ borderRadius: value * 3 + 'px !important' }" :style="{ borderRadius: value * 3.5 + 'px !important' }"
></div> ></div>
</template> </template>
</v-slider> </v-slider>

View file

@ -53,7 +53,7 @@
<v-icon v-else class="ml-4">mdi-chevron-down</v-icon> <v-icon v-else class="ml-4">mdi-chevron-down</v-icon>
</div> </div>
<div <div
class="d-flex justify-space-around" class="d-flex justify-space-between"
:class=" :class="
$store.state.tweaks.roundWatch && $store.state.tweaks.roundTweak > 0 $store.state.tweaks.roundWatch && $store.state.tweaks.roundTweak > 0
? $vuetify.theme.dark ? $vuetify.theme.dark

View file

@ -3,6 +3,7 @@ export const state = () => ({
speed: 1, speed: 1,
speedAutosave: null, speedAutosave: null,
preload: null, preload: null,
preloadUpTo: 100,
// quality: null, // quality: null,
// qualityAutoSwitch: null, // qualityAutoSwitch: null,
// shortFullscreen: null, // shortFullscreen: null,
@ -20,6 +21,8 @@ export const mutations = {
(JSON.parse(localStorage.getItem("speedAutosave")) === false) (JSON.parse(localStorage.getItem("speedAutosave")) === false)
); );
state.preload = JSON.parse(localStorage.getItem("preload")) === true; // defaults to false state.preload = JSON.parse(localStorage.getItem("preload")) === true; // defaults to false
state.preloadUpTo =
JSON.parse(localStorage.getItem("preloadUpTo")) || 100; // defaults to 100(percent)
} }
}, },
setLoop(state, payload) { setLoop(state, payload) {
@ -38,4 +41,8 @@ export const mutations = {
state.preload = payload; state.preload = payload;
localStorage.setItem("preload", payload); localStorage.setItem("preload", payload);
}, },
setPreloadUpTo(state, payload) {
state.preloadUpTo = payload;
localStorage.setItem("preloadUpTo", payload);
},
}; };