Started using custom video controls
This commit is contained in:
parent
da716fc3aa
commit
11865a6500
@ -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) == ""
|
||||||
|
@ -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
|
||||||
|
@ -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
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
37
scripts/Actions/Video.ts
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
@ -20,3 +20,4 @@ export * from "./SideBar"
|
|||||||
export * from "./StatusMessage"
|
export * from "./StatusMessage"
|
||||||
export * from "./Theme"
|
export * from "./Theme"
|
||||||
export * from "./Upload"
|
export * from "./Upload"
|
||||||
|
export * from "./Video"
|
@ -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")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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
26
styles/media.scarlet
Normal 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%)
|
@ -8,6 +8,10 @@ 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%
|
||||||
@ -15,3 +19,19 @@ const video-padding = 56.25%
|
|||||||
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
|
Loading…
Reference in New Issue
Block a user