Started using custom video controls

This commit is contained in:
Eduard Urbach 2018-12-07 09:54:17 +09:00
parent da716fc3aa
commit 11865a6500
13 changed files with 126 additions and 54 deletions

View File

@ -9,10 +9,17 @@ component AMVMini(amv *arn.AMV, user *arn.User)
AMVMiniFooter(amv, user) AMVMiniFooter(amv, user)
component AMVVideo(amv *arn.AMV) component AMVVideo(amv *arn.AMV)
.video-container .video-container(id=amv.ID)
video.video.lazy(controls, controlsList="nodownload") video.video.media-play-area.lazy.action(data-action="playVideo", data-trigger="click", data-media-id=amv.ID)
source(data-src="https://notify.moe/videos/amvs/" + amv.File, data-type="video/webm") source(data-src="https://notify.moe/videos/amvs/" + amv.File, data-type="video/webm")
//- button.media-play-button
//- RawIcon("play")
.video-controls
button.video-control.action(data-action="toggleFullscreen", data-trigger="click", data-id=amv.ID)
RawIcon("square-o")
component AMVFooter(amv *arn.AMV, user *arn.User) component AMVFooter(amv *arn.AMV, user *arn.User)
.amv-footer .amv-footer
if amv.Title.ByUser(user) == "" if amv.Title.ByUser(user) == ""

View File

@ -19,12 +19,13 @@ component SoundTrackContent(track *arn.SoundTrack, user *arn.User)
component SoundTrackMedia(track *arn.SoundTrack) component SoundTrackMedia(track *arn.SoundTrack)
if track.File != "" && track.HasMediaByService("Youtube") if track.File != "" && track.HasMediaByService("Youtube")
.soundtrack-media .soundtrack-media
.soundtrack-play-area.action(data-action="toggleAudio", data-trigger="click", data-audio-src="https://notify.moe/audio/" + track.File, data-soundtrack-id=track.ID) .media-play-area.action(data-action="toggleAudio", data-trigger="click", data-audio-src="https://notify.moe/audio/" + track.File, data-media-id=track.ID)
img.soundtrack-image.lazy(data-src="https://img.youtube.com/vi/" + track.MediaByService("Youtube")[0].ServiceID + "/0.jpg", alt=track.Title) img.media-image.lazy(data-src="https://img.youtube.com/vi/" + track.MediaByService("Youtube")[0].ServiceID + "/0.jpg", alt=track.Title)
button.soundtrack-play-button
button.media-play-button
RawIcon("play") RawIcon("play")
.soundtrack-visualizer .media-visualizer
.visualizer-box.visualizer-box-1 .visualizer-box.visualizer-box-1
.visualizer-box.visualizer-box-2 .visualizer-box.visualizer-box-2
.visualizer-box.visualizer-box-3 .visualizer-box.visualizer-box-3

View File

@ -24,7 +24,7 @@
min-height 112px min-height 112px
height 112px height 112px
.soundtrack-play-button .media-play-button
width 48px width 48px
height 48px height 48px
font-size 1rem font-size 1rem

View File

@ -17,7 +17,7 @@ component SoundTrackPage(track *arn.SoundTrack, user *arn.User)
if user != nil && media.Service == "Youtube" && track.File != "" if user != nil && media.Service == "Youtube" && track.File != ""
.buttons .buttons
button.action(data-action="playAudio", data-trigger="click", data-audio-src="/audio/" + track.File, data-soundtrack-id=track.ID) button.action(data-action="playAudio", data-trigger="click", data-audio-src="/audio/" + track.File, data-media-id=track.ID)
Icon("play") Icon("play")
span Play in background span Play in background

View File

@ -31,7 +31,7 @@ const soundtrack-margin = 1rem
iframe iframe
width 100% width 100%
.soundtrack-image .media-image
object-fit cover object-fit cover
width 100% width 100%
height 100% height 100%
@ -39,7 +39,7 @@ const soundtrack-margin = 1rem
filter brightness(100%) filter brightness(100%)
transition filter transition-speed ease transition filter transition-speed ease
.soundtrack-play-button .media-play-button
position absolute position absolute
top 50% top 50%
left 50% left 50%
@ -56,7 +56,7 @@ const soundtrack-margin = 1rem
.icon-play .icon-play
transform translateX(27%) transform translateX(27%)
.soundtrack-visualizer .media-visualizer
horizontal horizontal
justify-content center justify-content center
align-items center align-items center
@ -101,33 +101,6 @@ animation change-color
100% 100%
background-color hsl(235, 100%, 68%) background-color hsl(235, 100%, 68%)
.soundtrack-play-area
position absolute
top 0
left 0
width 100%
height 100%
cursor pointer
transition opacity 250ms ease
&.playing
.soundtrack-play-button
opacity 0
.soundtrack-visualizer
opacity 1
.soundtrack-image
filter brightness(0) !important
:hover
.soundtrack-play-button
color button-hover-color
background button-hover-background
.soundtrack-image
filter brightness(50%)
.soundtrack-footer .soundtrack-footer
media-footer media-footer
@ -142,7 +115,7 @@ animation change-color
border-bottom-right-radius 0 border-bottom-right-radius 0
border-top-right-radius 0 border-top-right-radius 0
.soundtrack-image .media-image
border-bottom-left-radius 0 border-bottom-left-radius 0
border-top-left-radius 0 border-top-left-radius 0

View File

@ -2,7 +2,7 @@ import AnimeNotifier from "../AnimeNotifier"
// Play audio // Play audio
export function playAudio(arn: AnimeNotifier, element: HTMLElement) { export function playAudio(arn: AnimeNotifier, element: HTMLElement) {
arn.audioPlayer.play(element.dataset.soundtrackId, element.dataset.audioSrc) arn.audioPlayer.play(element.dataset.mediaId, element.dataset.audioSrc)
} }
// Pause audio // Pause audio
@ -45,7 +45,7 @@ export function playPauseAudio(arn: AnimeNotifier) {
export function toggleAudio(arn: AnimeNotifier, element: HTMLElement) { export function toggleAudio(arn: AnimeNotifier, element: HTMLElement) {
// If we're clicking on the same track again, stop playing. // If we're clicking on the same track again, stop playing.
// Otherwise, start the track we clicked on. // Otherwise, start the track we clicked on.
if(arn.currentSoundTrackId && element.dataset.soundtrackId === arn.currentSoundTrackId) { if(arn.currentMediaId && element.dataset.mediaId === arn.currentMediaId) {
stopAudio(arn) stopAudio(arn)
} else { } else {
playAudio(arn, element) playAudio(arn, element)

View File

@ -1,5 +1,5 @@
import AnimeNotifier from "../AnimeNotifier" import AnimeNotifier from "../AnimeNotifier"
import Diff from "scripts/Diff"; import Diff from "scripts/Diff"
// Follow user // Follow user
export async function followUser(arn: AnimeNotifier, element: HTMLElement) { export async function followUser(arn: AnimeNotifier, element: HTMLElement) {

37
scripts/Actions/Video.ts Normal file
View File

@ -0,0 +1,37 @@
import AnimeNotifier from "../AnimeNotifier"
// Play video
export function playVideo(arn: AnimeNotifier, video: HTMLVideoElement) {
video.volume = arn.audioPlayer.volume
if(video.readyState >= 2) {
togglePlayVideo(video)
return
}
video.load()
video.addEventListener("loadeddata", () => {
togglePlayVideo(video)
})
}
function togglePlayVideo(video: HTMLVideoElement) {
if(video.paused) {
video.play()
} else {
video.pause()
}
}
// Toggle fullscreen
export function toggleFullscreen(arn: AnimeNotifier, button: HTMLElement) {
let elementId = button.dataset.id
let element = document.getElementById(elementId)
if(document.fullscreen) {
document.exitFullscreen()
} else {
element.requestFullscreen()
}
}

View File

@ -19,4 +19,5 @@ export * from "./Shop"
export * from "./SideBar" export * from "./SideBar"
export * from "./StatusMessage" export * from "./StatusMessage"
export * from "./Theme" export * from "./Theme"
export * from "./Upload" export * from "./Upload"
export * from "./Video"

View File

@ -34,7 +34,7 @@ export default class AnimeNotifier {
isLoading: boolean isLoading: boolean
diffCompletedForCurrentPath: boolean diffCompletedForCurrentPath: boolean
lastReloadContentPath: string lastReloadContentPath: string
currentSoundTrackId: string currentMediaId: string
serverEvents: ServerEvents serverEvents: ServerEvents
constructor(app: Application) { constructor(app: Application) {
@ -160,7 +160,7 @@ export default class AnimeNotifier {
Promise.resolve().then(() => this.displayLocalDates()), Promise.resolve().then(() => this.displayLocalDates()),
Promise.resolve().then(() => this.setSelectBoxValue()), Promise.resolve().then(() => this.setSelectBoxValue()),
Promise.resolve().then(() => this.textAreaFocus()), Promise.resolve().then(() => this.textAreaFocus()),
Promise.resolve().then(() => this.markPlayingSoundTrack()), Promise.resolve().then(() => this.markPlayingMedia()),
Promise.resolve().then(() => this.assignActions()), Promise.resolve().then(() => this.assignActions()),
Promise.resolve().then(() => this.updatePushUI()), Promise.resolve().then(() => this.updatePushUI()),
Promise.resolve().then(() => this.dragAndDrop()), Promise.resolve().then(() => this.dragAndDrop()),
@ -639,9 +639,9 @@ export default class AnimeNotifier {
} }
} }
markPlayingSoundTrack() { markPlayingMedia() {
for(let element of findAll("soundtrack-play-area")) { for(let element of findAll("media-play-area")) {
if(element.dataset.soundtrackId === this.currentSoundTrackId) { if(element.dataset.mediaId === this.currentMediaId) {
element.classList.add("playing") element.classList.add("playing")
} }
} }
@ -893,7 +893,7 @@ export default class AnimeNotifier {
lazyLoadVideo(video: HTMLVideoElement) { lazyLoadVideo(video: HTMLVideoElement) {
// Once the video becomes visible, load it // Once the video becomes visible, load it
video["became visible"] = () => { video["became visible"] = () => {
video.pause() // video.pause()
// Prevent context menu // Prevent context menu
video.addEventListener("contextmenu", e => e.preventDefault()) video.addEventListener("contextmenu", e => e.preventDefault())
@ -907,11 +907,16 @@ export default class AnimeNotifier {
element.src = element.dataset.src element.src = element.dataset.src
modified = true modified = true
} }
if(element.type !== element.dataset.type) {
element.type = element.dataset.type
modified = true
}
} }
if(modified) { if(modified) {
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
video.load() // video.load()
video.classList.add("element-found") video.classList.add("element-found")
}) })
} }

View File

@ -63,8 +63,8 @@ export default class AudioPlayer {
// Stop current track // Stop current track
this.stop() this.stop()
this.arn.currentSoundTrackId = trackId this.arn.currentMediaId = trackId
this.arn.markPlayingSoundTrack() this.arn.markPlayingMedia()
this.arn.loading(true) this.arn.loading(true)
// Mark as loading // Mark as loading
@ -187,7 +187,7 @@ export default class AudioPlayer {
// Stop // Stop
stop() { stop() {
this.arn.currentSoundTrackId = undefined this.arn.currentMediaId = undefined
// Remove CSS class "playing" // Remove CSS class "playing"
let playingElements = document.getElementsByClassName("playing") let playingElements = document.getElementsByClassName("playing")
@ -242,6 +242,8 @@ export default class AudioPlayer {
// Set volume // Set volume
setVolume(volume: number) { setVolume(volume: number) {
this.volume = volume
if(!this.gainNode) { if(!this.gainNode) {
return return
} }

26
styles/media.scarlet Normal file
View File

@ -0,0 +1,26 @@
.media-play-area
position absolute
top 0
left 0
width 100%
height 100%
cursor pointer
transition opacity 250ms ease
&.playing
.media-play-button
opacity 0
.media-visualizer
opacity 1
.media-image
filter brightness(0) !important
:hover
.media-play-button
color button-hover-color
background button-hover-background
.media-image
filter brightness(50%)

View File

@ -8,10 +8,30 @@ const video-padding = 56.25%
border-radius ui-element-border-radius border-radius ui-element-border-radius
overflow hidden overflow hidden
:hover
.video-controls
opacity 1
.video .video
position absolute position absolute
width 100% width 100%
height 100% height 100%
left 0 left 0
top 0 top 0
background-color black background-color black
.video-controls
position absolute
bottom 1rem
right 1rem
opacity 0
default-transition
.video-control
background transparent
border none
color white
font-size 1.2rem
::-webkit-media-controls
display none !important