0
0
Fork 0
mirror of https://github.com/VueTubeApp/VueTube synced 2024-11-23 11:45:15 +00:00

Merge pull request #281 from VueTubeApp/dev

Dev
This commit is contained in:
Kenny 2022-05-29 22:36:12 -04:00 committed by GitHub
commit c5a5f3d4da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 314 additions and 79 deletions

View file

@ -10,7 +10,7 @@
text text
to="/channel" to="/channel"
class="avatar-link mr-4" class="avatar-link mr-4"
style="height: 3rem; width: 3rem" style="height: 35px; width: 35px"
@click.prevent=" @click.prevent="
$store.dispatch( $store.dispatch(
'channel/fetchChannel', 'channel/fetchChannel',
@ -117,8 +117,8 @@
.avatar-thumbnail { .avatar-thumbnail {
border-radius: 50%; border-radius: 50%;
width: 48px; width: 35px;
height: 48px; height: 35px;
} }
.comment-content { .comment-content {

View file

@ -1,5 +1,11 @@
<template> <template>
<v-btn disabled fab text style="position: absolute; top: 0; right: 3.5rem"> <v-btn
fab
text
small
disabled
style="position: absolute; top: 0.25rem; right: 3rem"
>
<v-icon>mdi-closed-caption-outline</v-icon> <v-icon>mdi-closed-caption-outline</v-icon>
</v-btn> </v-btn>
</template> </template>

View file

@ -3,7 +3,8 @@
<v-btn <v-btn
fab fab
text text
style="position: absolute; top: 0; right: 0" small
style="position: absolute; top: 0.25rem; right: 0.25rem"
to="/home" to="/home"
color="white" color="white"
> >

View file

@ -2,8 +2,9 @@
<v-btn <v-btn
fab fab
text text
small
color="white" color="white"
style="position: absolute; bottom: 0.25rem; right: 0" style="position: absolute; bottom: 0.25rem; right: 0.25rem"
@click.stop="$emit('fullscreen')" @click.stop="$emit('fullscreen')"
> >
<v-icon>{{ fullscreen ? "mdi-fullscreen-exit" : "mdi-fullscreen" }}</v-icon> <v-icon>{{ fullscreen ? "mdi-fullscreen-exit" : "mdi-fullscreen" }}</v-icon>

View file

@ -1,5 +1,5 @@
<template> <template>
<!-- TODO: down: () => minimize, --> <!-- // TODO: down: () => minimize, -->
<div <div
ref="vidcontainer" ref="vidcontainer"
v-touch="{ v-touch="{
@ -19,43 +19,55 @@
ref="player" ref="player"
autoplay autoplay
width="100%" width="100%"
:height="isFullscreen ? '100%' : 'auto'"
:src="vidSrc" :src="vidSrc"
style="transition: filter 0.15s ease-in-out; max-height: 100vh" style="transition: filter 0.15s ease-in-out"
:class="controls ? 'dim' : ''" :class="controls || seeking ? 'dim' : ''"
:style="contain ? 'object-fit: contain;' : 'object-fit: cover;'" :style="contain ? 'object-fit: contain;' : 'object-fit: cover;'"
/> />
<!-- TODO: controls || seeking, take seeking out of <seekbar> component -->
<div
v-if="isFullscreen && controls"
style="
position: absolute;
width: calc(100% - 12rem);
left: 3rem;
top: 0.5rem;
"
>
<h4>{{ video.title }}</h4>
<div style="color: #aaa; font-size: 0.75rem">{{ video.channelName }}</div>
</div>
<!-- // TODO: merge the bottom 2 into 1 reusable component -->
<v-btn <v-btn
v-if="controls"
text text
tile tile
style=" style="
opacity: 0;
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 50%; width: 50%;
height: 100%; height: 100%;
opacity: 0;
" "
@dbclick.stop="$refs.player.currentTime -= $refs.player.duration / 10" @dblclick.stop="$refs.player.currentTime -= 10"
> >
<v-icon>mdi-rewind</v-icon> <v-icon>mdi-rewind</v-icon>
</v-btn> </v-btn>
<v-btn <v-btn
v-if="controls"
text text
tile tile
style=" style="
opacity: 0;
position: absolute; position: absolute;
top: 0; top: 0;
left: 50%; left: 50%;
width: 50%; width: 50%;
height: 100%; height: 100%;
opacity: 0;
" "
@dbclick.stop="$refs.player.currentTime += $refs.player.duration / 10" @dblclick.stop="$refs.player.currentTime += 10"
> >
<v-icon>mdi-fast-forward</v-icon> <v-icon>mdi-fast-forward</v-icon>
</v-btn> </v-btn>
@ -69,15 +81,72 @@
<captions /> <captions />
<close /> <close />
<v-btn
fab
text
small
style="
position: absolute;
top: calc(50% - 1.25rem);
left: calc(50% - 10rem);
"
color="white"
@click.stop="$refs.player.currentTime -= 5"
>
<v-icon size="1rem">mdi-rewind-5</v-icon>
</v-btn>
<v-btn
fab
text
style="
position: absolute;
top: calc(50% - 1.75rem);
left: calc(50% - 6.5rem);
"
color="white"
disabled
@click.stop=""
>
<v-icon size="2rem">mdi-skip-previous</v-icon>
</v-btn>
<playpause <playpause
v-if="$refs.player" v-if="$refs.player"
:video="$refs.player" :video="$refs.player"
@close="controls = false" @close="controls = false"
/> />
<v-btn
fab
text
style="
position: absolute;
top: calc(50% - 1.75rem);
left: calc(50% + 3rem);
"
color="white"
disabled
@click.stop=""
>
<v-icon size="2rem">mdi-skip-next</v-icon>
</v-btn>
<v-btn
fab
text
small
style="
position: absolute;
top: calc(50% - 1.25rem);
left: calc(50% + 7rem);
"
color="white"
@click.stop="$refs.player.currentTime += 5"
>
<v-icon size="1rem">mdi-fast-forward-5</v-icon>
</v-btn>
<watchtime v-if="$refs.player" :video="$refs.player" /> <watchtime v-if="$refs.player" :video="$refs.player" />
<quality /> <!-- // TODO: merge the bottom 2 into 1 reusable component -->
<speed /> <quality v-if="$refs.player" :video="$refs.player" :sources="sources" />
<speed v-if="$refs.player" :video="$refs.player" />
<fullscreen <fullscreen
:fullscreen="isFullscreen" :fullscreen="isFullscreen"
@fullscreen="(controls = $refs.player.paused), handleFullscreenChange()" @fullscreen="(controls = $refs.player.paused), handleFullscreenChange()"
@ -90,6 +159,8 @@
:fullscreen="isFullscreen" :fullscreen="isFullscreen"
:video="$refs.player" :video="$refs.player"
:sources="sources" :sources="sources"
:controls="controls"
@seeking="seeking = !seeking"
/> />
</div> </div>
</template> </template>
@ -123,11 +194,16 @@ export default {
type: Array, type: Array,
required: true, required: true,
}, },
video: {
type: Object,
required: true,
},
}, },
data() { data() {
return { return {
isFullscreen: false, isFullscreen: false,
controls: false, controls: false,
seeking: false,
contain: true, contain: true,
vidSrc: "", vidSrc: "",
}; };
@ -135,9 +211,11 @@ export default {
mounted() { mounted() {
console.log("sources", this.sources); console.log("sources", this.sources);
this.vidSrc = this.sources[this.sources.length - 1].url; this.vidSrc = this.sources[this.sources.length - 1].url;
// TODO: detect orientation change and enter fullscreen
// TODO: detect video loading state and send this.loading to play button :loading = loading
}, },
beforeDestroy() { beforeDestroy() {
this.exitFullscreen(); if (this.isFullscreen) this.exitFullscreen();
}, },
methods: { methods: {
handleFullscreenChange() { handleFullscreenChange() {
@ -182,6 +260,9 @@ export default {
<style> <style>
.dim { .dim {
filter: brightness(50%); filter: brightness(42%);
}
.invisible {
opacity: 0;
} }
</style> </style>

View file

@ -1,5 +1,11 @@
<template> <template>
<v-btn fab text disabled style="position: absolute; top: 0; right: 7rem"> <v-btn
fab
text
small
disabled
style="position: absolute; top: 0.25rem; right: 6rem"
>
<v-icon>mdi-sync</v-icon> <v-icon>mdi-sync</v-icon>
</v-btn> </v-btn>
</template> </template>

View file

@ -1,5 +1,11 @@
<template> <template>
<v-btn fab text disabled style="position: absolute; top: 0; left: 0"> <v-btn
fab
text
small
disabled
style="position: absolute; top: 0.25rem; left: 0.25rem"
>
<v-icon>mdi-chevron-down</v-icon> <v-icon>mdi-chevron-down</v-icon>
</v-btn> </v-btn>
</template> </template>

View file

@ -2,20 +2,15 @@
<v-btn <v-btn
fab fab
text text
style=" large
width: 5rem; style="position: absolute; top: calc(50% - 2rem); left: calc(50% - 2rem)"
height: 5rem;
position: absolute;
top: calc(50% - 2.5rem);
left: calc(50% - 2.5rem);
"
color="white" color="white"
@click.stop=" @click.stop="
(paused = !video.paused), (paused = !video.paused),
video.paused ? (video.play(), $emit('close')) : video.pause() video.paused ? (video.play(), $emit('close')) : video.pause()
" "
> >
<v-icon size="5rem"> <v-icon size="3.5rem">
{{ paused ? "mdi-play" : "mdi-pause" }} {{ paused ? "mdi-play" : "mdi-pause" }}
</v-icon> </v-icon>
</v-btn> </v-btn>

View file

@ -1,10 +1,66 @@
<template> <template>
<v-btn <div>
fab <v-bottom-sheet
text v-model="sheet"
disabled :attach="$parent.$refs.vidcontainer"
style="position: absolute; bottom: 0.25rem; right: 3.5rem" scrollable
> >
HD <template #activator="{ on, attrs }">
</v-btn> <v-btn
fab
text
small
style="position: absolute; bottom: 0.25rem; right: 3rem"
v-bind="attrs"
v-on="on"
>
{{ sources.find((src) => src.url == video.src).qualityLabel }}
</v-btn>
</template>
<v-card
v-touch="{
down: () => (sheet = false),
}"
class="background"
>
<v-subheader>Quality for current video</v-subheader>
<v-card-text style="max-height: 50vh" class="pa-0">
<v-list-item
v-for="src in sources"
:key="src"
@click="(sheet = false), (video.src = src.url)"
>
<v-list-item-avatar>
<v-icon
:color="
video.src === src.url
? 'primary'
: $vuetify.theme.dark
? 'background lighten-2'
: 'background darken-2'
"
v-text="
video.src === src.url
? 'mdi-radiobox-marked'
: 'mdi-radiobox-blank'
"
></v-icon>
</v-list-item-avatar>
<v-list-item-title>
{{ src.qualityLabel }} ({{ src.quality }})
</v-list-item-title>
</v-list-item>
</v-card-text>
</v-card>
</v-bottom-sheet>
</div>
</template> </template>
<script>
export default {
props: ["video", "sources"],
data: () => ({
sheet: false,
}),
};
</script>

View file

@ -10,30 +10,38 @@
<v-progress-linear <v-progress-linear
query query
active active
style="width: 100%" style="width: 100%; background: #ffffff22"
background-opacity="0.5" background-opacity="0.5"
background-color="primary" background-color="primary"
:buffer-value="buffered" :buffer-value="buffered"
:value="percent" :value="percent"
color="primary" color="primary"
height="2" height="3"
:style="
fullscreen
? 'width: calc(100% - 2rem); left: 1rem; position: absolute; bottom: 3rem;'
: 'width: 100%'
"
/> />
<!-- Scrubber --> <!-- Scrubber -->
<v-slider <v-slider
id="scrubber"
hide-details hide-details
height="2" height="2"
dense dense
style="position: absolute; z-index: 69420" track-color="transparent"
:class="!controls && !fullscreen && !scrubbing ? 'invisible' : ''"
style="position: absolute; z-index: 2"
:style=" :style="
fullscreen fullscreen
? 'width: calc(100% - 2rem); left: 1rem; bottom: 4rem;' ? 'width: calc(100% - 2rem); left: 1rem; bottom: 3rem;'
: 'width: 100%; left: 0; bottom: 0;' : 'width: calc(100% - 0.8rem); left: 0.4rem; bottom: 0;'
" "
:thumb-size="0" :thumb-size="0"
:max="duration" :max="duration"
:value="progress" :value="progress"
@start="scrubbing = true" @start="(scrubbing = true), $emit('seeking')"
@end="scrubbing = false" @end="(scrubbing = false), $emit('seeking')"
@change="scrub($event)" @change="scrub($event)"
@input="scrubbing ? seek($event) : null" @input="scrubbing ? seek($event) : null"
> >
@ -62,7 +70,7 @@
<script> <script>
export default { export default {
props: ["sources", "video", "fullscreen"], props: ["sources", "video", "controls", "fullscreen"],
data() { data() {
return { return {

View file

@ -1,10 +1,64 @@
<template> <template>
<v-btn <div>
fab <v-bottom-sheet
text v-model="sheet"
disabled :attach="$parent.$refs.vidcontainer"
style="position: absolute; bottom: 0.25rem; right: 7rem" scrollable
> >
1X <template #activator="{ on, attrs }">
</v-btn> <v-btn
fab
text
small
style="position: absolute; bottom: 0.25rem; right: 6rem"
v-bind="attrs"
v-on="on"
>
{{ video.playbackRate }}X
</v-btn>
</template>
<v-card
v-touch="{
down: () => (sheet = false),
}"
class="background"
>
<v-subheader>Playback Speed</v-subheader>
<v-card-text style="height: 50vh" class="pa-0">
<v-list-item
v-for="sped in speeds"
:key="sped"
@click="(sheet = false), (video.playbackRate = sped)"
>
<!-- // TODO: save playbackRate to localStorage and manage via store/video/index.js -->
<v-list-item-avatar>
<v-icon
:color="
video.playbackRate === sped
? 'primary'
: $vuetify.theme.dark
? 'background lighten-2'
: 'background darken-2'
"
v-text="
video.playbackRate === sped ? 'mdi-check' : 'mdi-speedometer'
"
></v-icon>
</v-list-item-avatar>
<v-list-item-title>{{ sped }}X</v-list-item-title>
</v-list-item>
</v-card-text>
</v-card>
</v-bottom-sheet>
</div>
</template> </template>
<script>
export default {
props: ["video"],
data: () => ({
sheet: false,
speeds: [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 3, 4, 8, 16],
}),
};
</script>

View file

@ -2,14 +2,14 @@
<div <div
style=" style="
color: #fff; color: #fff;
left: 1.25rem; left: 1rem;
bottom: 1.25rem; bottom: 1rem;
font-size: 0.75rem; font-size: 0.75rem;
position: absolute; position: absolute;
" "
> >
{{ watched }} {{ watched }}
<span style="color: #999"> / {{ duration }} </span> <span style="color: #aaa"> / {{ duration }} </span>
</div> </div>
</template> </template>

View file

@ -1,14 +1,7 @@
<template> <template>
<v-card <v-card
class="entry videoRenderer background" class="entry videoRenderer background overflow-hidden"
:to="`/watch?v=${vidId}`" :to="`/watch?v=${vidId}`"
:class="
roundThumb && roundTweak > 0
? $vuetify.theme.dark
? 'lighten-1'
: 'darken-1'
: ''
"
:style="{ :style="{
borderRadius: roundThumb ? `${roundTweak / 2}rem` : '0', borderRadius: roundThumb ? `${roundTweak / 2}rem` : '0',
margin: margin:
@ -21,7 +14,7 @@
:aspect-ratio="16 / 9" :aspect-ratio="16 / 9"
:src="$youtube.getThumbnail(vidId, 'max', thumbnails)" :src="$youtube.getThumbnail(vidId, 'max', thumbnails)"
:style="{ :style="{
borderRadius: roundThumb ? `${roundTweak / 4}rem` : '0', borderRadius: roundThumb ? `${roundTweak / 12}rem` : '0',
}" }"
/> />
<div <div
@ -32,13 +25,26 @@
v-text="thumbnailOverlayText" v-text="thumbnailOverlayText"
/> />
</div> </div>
<div id="details"> <div
id="details"
class="background mt-1"
:class="
roundThumb && roundTweak > 0
? $vuetify.theme.dark
? 'lighten-1'
: 'darken-1'
: ''
"
:style="{
borderRadius: roundThumb ? `${roundTweak / 12}rem` : '0',
}"
>
<a <a
class="avatar-link pl-2 pt-2"
@click.prevent=" @click.prevent="
$store.dispatch('channel/fetchChannel', channelUrl), $store.dispatch('channel/fetchChannel', channelUrl),
$router.push('/channel') $router.push('/channel')
" "
class="avatar-link pl-2 pt-2"
> >
<v-img class="avatar-thumbnail" :src="channelIcon" /> <v-img class="avatar-thumbnail" :src="channelIcon" />
</a> </a>

View file

@ -248,6 +248,12 @@ export default {
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
} }
.transparent-lighten-1 {
background: #ffffff22;
}
.transparent-darken-1 {
background: #00000022;
}
.debug { .debug {
outline: 1px solid red; outline: 1px solid red;
} }

View file

@ -1,9 +1,14 @@
<template> <template>
<div class="background" id="watch-body"> <div class="background" id="watch-body">
<div id="player-container"> <div id="player-container">
<!-- TODO: move component to default.vue --> <!-- // TODO: move component to default.vue -->
<!-- TODO: pass sources through vuex instead of props --> <!-- // TODO: pass sources through vuex instead of props -->
<player v-if="sources.length > 0" ref="player" :sources="sources" /> <player
v-if="sources.length > 0 && video.title && video.channelName"
ref="player"
:video="video"
:sources="sources"
/>
</div> </div>
<div <div
@ -46,23 +51,26 @@
<v-icon class="ml-4" v-if="showMore">mdi-chevron-up</v-icon> <v-icon class="ml-4" v-if="showMore">mdi-chevron-up</v-icon>
<v-icon class="ml-4" v-else>mdi-chevron-down</v-icon> <v-icon class="ml-4" v-else>mdi-chevron-down</v-icon>
</div> </div>
<div class="d-flex pl-6"> <div class="d-flex pl-4">
<v-btn <v-btn
v-for="(item, index) in interactions" v-for="(item, index) in interactions"
:key="index" :key="index"
text text
fab fab
no-caps
class="vertical-button mx-1" class="vertical-button mx-1"
elevation="0" elevation="0"
style="width: 4.2rem !important; height: 4.2rem !important" style="
width: 4.2rem !important;
height: 4.2rem !important;
text-transform: none !important;
"
:disabled="item.disabled" :disabled="item.disabled"
@click="callMethodByName(item.actionName)" @click="callMethodByName(item.actionName)"
> >
<v-icon v-text="item.icon" /> <v-icon v-text="item.icon" />
<div <div
class="mt-2" class="mt-1"
style="font-size: 0.66rem" style="font-size: 0.6rem"
v-text="item.value || item.name" v-text="item.value || item.name"
/> />
</v-btn> </v-btn>
@ -214,17 +222,17 @@
/> />
<swipeable-bottom-sheet <swipeable-bottom-sheet
v-if="loaded && video.commentData"
v-model="showComments" v-model="showComments"
hide-overlay hide-overlay
persistent persistent
no-click-animation no-click-animation
attach="#content-container" attach="#content-container"
v-if="loaded && video.commentData"
> >
<mainCommentRenderer <mainCommentRenderer
:defaultContinuation="video.commentContinuation"
:commentData="video.commentData"
v-model="showComments" v-model="showComments"
:comment-data="video.commentData"
:default-continuation="video.commentContinuation"
></mainCommentRenderer> ></mainCommentRenderer>
</swipeable-bottom-sheet> </swipeable-bottom-sheet>
@ -316,6 +324,7 @@ export default {
this.loaded = false; this.loaded = false;
this.$youtube.getVid(this.$route.query.v).then((result) => { this.$youtube.getVid(this.$route.query.v).then((result) => {
// TODO: add other resolutions as well
this.sources = result.availableResolutions; this.sources = result.availableResolutions;
console.log("Video info data", result); console.log("Video info data", result);
this.video = result; this.video = result;