Heavily improved audio player
This commit is contained in:
parent
26703c467a
commit
950155bdd2
@ -2,23 +2,33 @@ component SoundTrack(track *arn.SoundTrack)
|
||||
SoundTrackMedia(track, track.Media[0])
|
||||
|
||||
component SoundTrackMedia(track *arn.SoundTrack, media *arn.ExternalMedia)
|
||||
.sound-track.mountable(id=track.ID)
|
||||
.soundtrack.mountable(id=track.ID)
|
||||
SoundTrackContent(track, media)
|
||||
SoundTrackFooter(track)
|
||||
|
||||
component SoundTrackContent(track *arn.SoundTrack, media *arn.ExternalMedia)
|
||||
.sound-track-content
|
||||
.soundtrack-content
|
||||
if track.MainAnime() != nil
|
||||
a.sound-track-anime-link.ajax(href="/anime/" + track.MainAnime().ID)
|
||||
img.sound-track-anime-image.lazy(data-src=track.MainAnime().Image("medium"), data-webp="true", alt=track.MainAnime().Title.Canonical, title=track.MainAnime().Title.Canonical)
|
||||
a.soundtrack-anime-link.ajax(href="/anime/" + track.MainAnime().ID)
|
||||
img.soundtrack-anime-image.lazy(data-src=track.MainAnime().Image("medium"), data-webp="true", alt=track.MainAnime().Title.Canonical, title=track.MainAnime().Title.Canonical)
|
||||
|
||||
if track.File != "" && media.Service == "Youtube"
|
||||
img.soundtrack-image.action.lazy(data-action="playAudio", data-trigger="click", data-audio-src="https://notify.moe/audio/" + track.File, data-src="https://img.youtube.com/vi/" + media.ServiceID + "/maxresdefault.jpg", alt=track.Title)
|
||||
.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)
|
||||
img.soundtrack-image.lazy(data-src="https://img.youtube.com/vi/" + media.ServiceID + "/maxresdefault.jpg", alt=track.Title)
|
||||
button.soundtrack-play-button
|
||||
RawIcon("play")
|
||||
|
||||
.soundtrack-visualizer
|
||||
.visualizer-box.visualizer-box-1
|
||||
.visualizer-box.visualizer-box-2
|
||||
.visualizer-box.visualizer-box-3
|
||||
|
||||
else
|
||||
ExternalMedia(media)
|
||||
|
||||
component SoundTrackFooter(track *arn.SoundTrack)
|
||||
.sound-track-footer
|
||||
.soundtrack-footer
|
||||
if track.Title == ""
|
||||
a.ajax(href=track.Link() + "/edit") untitled
|
||||
else
|
||||
|
@ -9,4 +9,4 @@ component AnimeTracks(anime *arn.Anime, tracks []*arn.SoundTrack)
|
||||
.anime-soundtrack.mountable(data-mountable-type="track")
|
||||
.video-container
|
||||
iframe.video.lazy(data-src=track.Media[0].EmbedLink(), allowfullscreen="allowfullscreen")
|
||||
a.sound-track-footer.ajax(href=track.Link())= track.Title
|
||||
a.soundtrack-footer.ajax(href=track.Link())= track.Title
|
@ -6,7 +6,7 @@ component TrackList(tracks []*arn.SoundTrack, viewUser *arn.User, user *arn.User
|
||||
if len(tracks) == 0
|
||||
p.no-data.mountable= viewUser.Nick + " hasn't added any tracks yet."
|
||||
else
|
||||
.sound-tracks
|
||||
.soundtracks
|
||||
each track in tracks
|
||||
SoundTrack(track)
|
||||
|
@ -1,17 +1,17 @@
|
||||
component Track(track *arn.SoundTrack, user *arn.User)
|
||||
SoundTrackTabs(track, user)
|
||||
|
||||
.sound-track-full-page
|
||||
.soundtrack-full-page
|
||||
if track.Title == ""
|
||||
h1.mountable untitled
|
||||
else
|
||||
h1.mountable= track.Title
|
||||
|
||||
.widget-form.sound-track-media-list
|
||||
.widget-form.soundtrack-media-list
|
||||
each media in track.Media
|
||||
.widget.mountable
|
||||
h3.widget-title= media.Service
|
||||
.sound-track-media.video-container
|
||||
.soundtrack-media.video-container
|
||||
iframe.lazy.video(data-src=media.EmbedLink(), allowfullscreen="allowfullscreen")
|
||||
|
||||
if user != nil && media.Service == "Youtube" && track.File != ""
|
||||
@ -23,10 +23,10 @@ component Track(track *arn.SoundTrack, user *arn.User)
|
||||
.widget.mountable
|
||||
h3.widget-title Anime
|
||||
|
||||
.sound-track-anime-list
|
||||
.soundtrack-anime-list
|
||||
each anime in track.Anime()
|
||||
a.sound-track-anime-list-item.ajax(href=anime.Link(), title=anime.Title.ByUser(user))
|
||||
img.sound-track-anime-list-item-image.lazy(data-src=anime.Image("small"), data-webp="true", alt=anime.Title.ByUser(user))
|
||||
a.soundtrack-anime-list-item.ajax(href=anime.Link(), title=anime.Title.ByUser(user))
|
||||
img.soundtrack-anime-list-item-image.lazy(data-src=anime.Image("small"), data-webp="true", alt=anime.Title.ByUser(user))
|
||||
|
||||
if len(track.Beatmaps()) > 0
|
||||
.widget.mountable
|
||||
|
@ -1,15 +1,18 @@
|
||||
.sound-track-media-list
|
||||
.soundtrack-media-list
|
||||
vertical
|
||||
|
||||
.sound-track-media
|
||||
.soundtrack-media
|
||||
width 100%
|
||||
position relative
|
||||
|
||||
iframe
|
||||
width 100%
|
||||
|
||||
.sound-track-anime-list
|
||||
.soundtrack-anime-list
|
||||
horizontal-wrap
|
||||
|
||||
.sound-track-anime-list-item
|
||||
.soundtrack-anime-list-item
|
||||
anime-mini-item
|
||||
|
||||
.sound-track-anime-list-item-image
|
||||
.soundtrack-anime-list-item-image
|
||||
anime-mini-item-image
|
@ -14,7 +14,7 @@ component SoundTracks(tracks []*arn.SoundTrack, loadMoreIndex int, user *arn.Use
|
||||
Icon("pencil")
|
||||
span Edit draft
|
||||
|
||||
#load-more-target.sound-tracks
|
||||
#load-more-target.soundtracks
|
||||
SoundTracksScrollable(tracks, user)
|
||||
|
||||
if loadMoreIndex != 0
|
||||
|
@ -1,14 +1,14 @@
|
||||
.sound-tracks
|
||||
.soundtracks
|
||||
horizontal-wrap
|
||||
justify-content space-around
|
||||
|
||||
.sound-track
|
||||
.soundtrack
|
||||
vertical
|
||||
flex 1
|
||||
flex-basis 500px
|
||||
padding 1rem
|
||||
|
||||
.sound-track-content
|
||||
.soundtrack-content
|
||||
horizontal
|
||||
border-radius 3px
|
||||
overflow hidden
|
||||
@ -21,8 +21,95 @@
|
||||
object-fit cover
|
||||
width 100%
|
||||
height 200px
|
||||
filter brightness(100%)
|
||||
transition filter 250ms ease
|
||||
|
||||
.sound-track-footer
|
||||
.soundtrack-play-button
|
||||
position absolute
|
||||
top 50%
|
||||
left 50%
|
||||
transform translate(-50%, -50%)
|
||||
border-radius 50%
|
||||
width 92px
|
||||
height 92px
|
||||
font-size 3rem
|
||||
color rgba(0, 0, 0, 0.15)
|
||||
background rgba(255, 255, 255, 0.9)
|
||||
pointer-events none
|
||||
|
||||
.icon-play
|
||||
transform translateX(27%)
|
||||
|
||||
.soundtrack-visualizer
|
||||
horizontal
|
||||
justify-content center
|
||||
align-items center
|
||||
pointer-events none
|
||||
position absolute
|
||||
top 0
|
||||
left 0
|
||||
width 100%
|
||||
height 100%
|
||||
opacity 0
|
||||
transition opacity 250ms ease
|
||||
|
||||
.visualizer-box
|
||||
width 3px
|
||||
height 15px
|
||||
margin 0.2rem
|
||||
border-radius 1px
|
||||
transition all 250ms linear
|
||||
animation scale-vertically 300ms infinite ease, change-color 1s infinite ease
|
||||
animation-direction alternate
|
||||
|
||||
.visualizer-box-1
|
||||
animation-delay 0
|
||||
|
||||
.visualizer-box-2
|
||||
animation-delay 100ms
|
||||
|
||||
.visualizer-box-3
|
||||
animation-delay 200ms
|
||||
|
||||
animation scale-vertically
|
||||
0%
|
||||
transform scaleY(0.3)
|
||||
opacity 0.8
|
||||
100%
|
||||
transform scaleY(1)
|
||||
opacity 1
|
||||
|
||||
animation change-color
|
||||
0%
|
||||
background-color hsl(45, 100%, 68%)
|
||||
100%
|
||||
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)
|
||||
|
||||
:hover
|
||||
.soundtrack-play-button
|
||||
color button-hover-color
|
||||
background button-hover-background
|
||||
|
||||
.soundtrack-footer
|
||||
text-align center
|
||||
margin-bottom 1rem
|
||||
margin-top 0.4rem
|
||||
@ -31,13 +118,13 @@
|
||||
span
|
||||
opacity 0.65
|
||||
|
||||
.sound-track-anime-link
|
||||
.soundtrack-anime-link
|
||||
display none
|
||||
|
||||
> 800px
|
||||
.sound-track-anime-link
|
||||
.soundtrack-anime-link
|
||||
display block
|
||||
|
||||
.sound-track-anime-image
|
||||
.soundtrack-anime-image
|
||||
width 142px
|
||||
height 200px
|
@ -8,23 +8,22 @@ var audioPlayerPlay = document.getElementById("audio-player-play")
|
||||
var audioPlayerPause = document.getElementById("audio-player-pause")
|
||||
|
||||
// Play audio file
|
||||
export function playAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
export function playAudio(arn: AnimeNotifier, element: HTMLElement) {
|
||||
if(!audioContext) {
|
||||
audioContext = new AudioContext()
|
||||
}
|
||||
|
||||
playID++
|
||||
|
||||
// Stop existing audioNode
|
||||
if(audioNode) {
|
||||
audioNode.stop()
|
||||
audioNode.disconnect()
|
||||
audioNode = null
|
||||
}
|
||||
// Stop current track
|
||||
stopAudio(arn)
|
||||
|
||||
arn.currentSoundTrackId = element.dataset.soundtrackId
|
||||
element.classList.add("playing")
|
||||
|
||||
// Request
|
||||
let request = new XMLHttpRequest()
|
||||
request.open("GET", button.dataset.audioSrc, true)
|
||||
request.open("GET", element.dataset.audioSrc, true)
|
||||
request.responseType = "arraybuffer"
|
||||
|
||||
request.onload = () => {
|
||||
@ -38,8 +37,7 @@ export function playAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
|
||||
audioNode.onended = (event: MediaStreamErrorEvent) => {
|
||||
if(currentPlayCount === playID) {
|
||||
audioPlayer.classList.add("fade-out")
|
||||
audioNode.disconnect()
|
||||
stopAudio(arn)
|
||||
}
|
||||
}
|
||||
}, console.error)
|
||||
@ -53,6 +51,38 @@ export function playAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
audioPlayerPause.classList.remove("fade-out")
|
||||
}
|
||||
|
||||
// Stop audio
|
||||
export function stopAudio(arn: AnimeNotifier) {
|
||||
if(!audioNode) {
|
||||
return
|
||||
}
|
||||
|
||||
audioNode.stop()
|
||||
audioNode.disconnect()
|
||||
audioNode = null
|
||||
|
||||
arn.currentSoundTrackId = undefined
|
||||
|
||||
// Remove CSS class "playing"
|
||||
let playingElements = document.getElementsByClassName("playing")
|
||||
|
||||
for(let playing of playingElements) {
|
||||
playing.classList.remove("playing")
|
||||
}
|
||||
|
||||
// Fade out sidebar player
|
||||
audioPlayer.classList.add("fade-out")
|
||||
}
|
||||
|
||||
// Toggle audio
|
||||
export function toggleAudio(arn: AnimeNotifier, element: HTMLElement) {
|
||||
if(!arn.currentSoundTrackId) {
|
||||
playAudio(arn, element)
|
||||
} else {
|
||||
stopAudio(arn)
|
||||
}
|
||||
}
|
||||
|
||||
// Pause audio
|
||||
export function pauseAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
if(!audioNode) {
|
||||
|
@ -32,6 +32,7 @@ export class AnimeNotifier {
|
||||
mainPageLoaded: boolean
|
||||
isLoading: boolean
|
||||
lastReloadContentPath: string
|
||||
currentSoundTrackId: string
|
||||
|
||||
elementFound: MutationQueue
|
||||
elementNotFound: MutationQueue
|
||||
@ -158,6 +159,7 @@ export class AnimeNotifier {
|
||||
Promise.resolve().then(() => this.lazyLoad()),
|
||||
Promise.resolve().then(() => this.displayLocalDates()),
|
||||
Promise.resolve().then(() => this.setSelectBoxValue()),
|
||||
Promise.resolve().then(() => this.markPlayingSoundTrack()),
|
||||
Promise.resolve().then(() => this.assignActions()),
|
||||
Promise.resolve().then(() => this.updatePushUI()),
|
||||
Promise.resolve().then(() => this.dragAndDrop()),
|
||||
@ -357,6 +359,14 @@ export class AnimeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
markPlayingSoundTrack() {
|
||||
for(let element of findAll("soundtrack-play-area")) {
|
||||
if(element.dataset.soundtrackId === this.currentSoundTrackId) {
|
||||
element.classList.add("playing")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelectBoxValue() {
|
||||
for(let element of document.getElementsByTagName("select")) {
|
||||
element.value = element.getAttribute("value")
|
||||
|
Loading…
Reference in New Issue
Block a user