Audio player rework
This commit is contained in:
parent
2cbf7c4e5c
commit
eb5a8e49aa
@ -1,177 +1,44 @@
|
||||
import { AnimeNotifier } from "../AnimeNotifier"
|
||||
|
||||
var audioContext: AudioContext
|
||||
var audioNode: AudioBufferSourceNode
|
||||
var gainNode: GainNode
|
||||
var volume = 0.5
|
||||
var volumeTimeConstant = 0.01
|
||||
var volumeSmoothingDelay = 0.05
|
||||
var targetSpeed = 1.0
|
||||
var playId = 0
|
||||
var audioPlayer = document.getElementById("audio-player")
|
||||
var audioPlayerPlay = document.getElementById("audio-player-play") as HTMLButtonElement
|
||||
var audioPlayerPause = document.getElementById("audio-player-pause") as HTMLButtonElement
|
||||
var trackLink = document.getElementById("audio-player-track-title") as HTMLLinkElement
|
||||
var animeInfo = document.getElementById("audio-player-anime-info") as HTMLElement
|
||||
var animeLink = document.getElementById("audio-player-anime-link") as HTMLLinkElement
|
||||
var animeImage = document.getElementById("audio-player-anime-image") as HTMLImageElement
|
||||
var lastRequest: XMLHttpRequest
|
||||
|
||||
// Play audio
|
||||
export function playAudio(arn: AnimeNotifier, element: HTMLElement) {
|
||||
playAudioFile(arn, element.dataset.soundtrackId, element.dataset.audioSrc)
|
||||
arn.audioPlayer.play(element.dataset.soundtrackId, element.dataset.audioSrc)
|
||||
}
|
||||
|
||||
// Play audio file
|
||||
function playAudioFile(arn: AnimeNotifier, trackId: string, trackUrl: string) {
|
||||
if(!audioContext) {
|
||||
audioContext = new AudioContext()
|
||||
gainNode = audioContext.createGain()
|
||||
gainNode.gain.setTargetAtTime(volume, audioContext.currentTime + volumeSmoothingDelay, volumeTimeConstant)
|
||||
}
|
||||
|
||||
playId++
|
||||
let currentPlayId = playId
|
||||
|
||||
if(lastRequest) {
|
||||
lastRequest.abort()
|
||||
lastRequest = null
|
||||
}
|
||||
|
||||
// Stop current track
|
||||
stopAudio(arn)
|
||||
|
||||
arn.currentSoundTrackId = trackId
|
||||
arn.markPlayingSoundTrack()
|
||||
arn.loading(true)
|
||||
|
||||
// Mark as loading
|
||||
audioPlayer.classList.add("loading-network")
|
||||
audioPlayer.classList.remove("decoding-audio")
|
||||
audioPlayer.classList.remove("decoded")
|
||||
|
||||
// Request
|
||||
let request = new XMLHttpRequest()
|
||||
request.open("GET", trackUrl, true)
|
||||
request.responseType = "arraybuffer"
|
||||
|
||||
request.onload = () => {
|
||||
if(currentPlayId !== playId) {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark as loading finished, now decoding starts
|
||||
audioPlayer.classList.add("decoding-audio")
|
||||
arn.loading(false)
|
||||
|
||||
audioContext.decodeAudioData(request.response, async buffer => {
|
||||
if(currentPlayId !== playId) {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark as ready
|
||||
audioPlayer.classList.add("decoded")
|
||||
|
||||
audioNode = audioContext.createBufferSource()
|
||||
audioNode.buffer = buffer
|
||||
audioNode.connect(gainNode)
|
||||
gainNode.connect(audioContext.destination)
|
||||
audioNode.playbackRate.setValueAtTime(targetSpeed, 0)
|
||||
audioNode.start(0)
|
||||
|
||||
audioNode.onended = (event: MediaStreamErrorEvent) => {
|
||||
if(currentPlayId !== playId) {
|
||||
return
|
||||
}
|
||||
|
||||
playNextTrack(arn)
|
||||
// stopAudio(arn)
|
||||
}
|
||||
}, console.error)
|
||||
}
|
||||
|
||||
request.onerror = () => {
|
||||
arn.loading(false)
|
||||
}
|
||||
|
||||
lastRequest = request
|
||||
request.send()
|
||||
|
||||
// Update track info
|
||||
updateTrackInfo(trackId)
|
||||
|
||||
// Show audio player
|
||||
audioPlayer.classList.remove("fade-out")
|
||||
audioPlayerPlay.classList.add("fade-out")
|
||||
audioPlayerPause.classList.remove("fade-out")
|
||||
// Pause audio
|
||||
export function pauseAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
arn.audioPlayer.pause()
|
||||
}
|
||||
|
||||
// Update track info
|
||||
async function updateTrackInfo(trackId: string) {
|
||||
// Set track title
|
||||
let trackInfoResponse = await fetch("/api/soundtrack/" + trackId)
|
||||
let track = await trackInfoResponse.json()
|
||||
trackLink.href = "/soundtrack/" + track.id
|
||||
trackLink.innerText = track.title
|
||||
|
||||
let animeId = ""
|
||||
|
||||
for(let tag of (track.tags as string[])) {
|
||||
if(tag.startsWith("anime:")) {
|
||||
animeId = tag.split(":")[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set anime info
|
||||
if(animeId !== "") {
|
||||
animeInfo.classList.remove("hidden")
|
||||
let animeResponse = await fetch("/api/anime/" + animeId)
|
||||
let anime = await animeResponse.json()
|
||||
animeLink.title = anime.title.canonical
|
||||
animeLink.href = "/anime/" + anime.id
|
||||
animeImage.dataset.src = "//media.notify.moe/images/anime/medium/" + anime.id + ".jpg"
|
||||
animeImage.classList.remove("hidden")
|
||||
animeImage["became visible"]()
|
||||
}
|
||||
// Resume audio
|
||||
export function resumeAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
arn.audioPlayer.resume()
|
||||
}
|
||||
|
||||
// Stop audio
|
||||
export function stopAudio(arn: AnimeNotifier) {
|
||||
arn.currentSoundTrackId = undefined
|
||||
arn.audioPlayer.stop()
|
||||
}
|
||||
|
||||
// Remove CSS class "playing"
|
||||
let playingElements = document.getElementsByClassName("playing")
|
||||
// Play previous track
|
||||
export async function playPreviousTrack(arn: AnimeNotifier) {
|
||||
arn.audioPlayer.previous()
|
||||
}
|
||||
|
||||
for(let playing of playingElements) {
|
||||
playing.classList.remove("playing")
|
||||
}
|
||||
// Play next track
|
||||
export async function playNextTrack(arn: AnimeNotifier) {
|
||||
arn.audioPlayer.next()
|
||||
}
|
||||
|
||||
// Fade out sidebar player
|
||||
// audioPlayer.classList.add("fade-out")
|
||||
// Set volume
|
||||
export function setVolume(arn: AnimeNotifier, element: HTMLInputElement) {
|
||||
let volume = parseFloat(element.value) / 100.0
|
||||
arn.audioPlayer.setVolume(volume)
|
||||
}
|
||||
|
||||
// Remove title
|
||||
trackLink.href = ""
|
||||
trackLink.innerText = ""
|
||||
|
||||
// Hide anime info
|
||||
animeLink.href = ""
|
||||
animeInfo.classList.add("hidden")
|
||||
animeImage.classList.add("hidden")
|
||||
|
||||
// Show play button
|
||||
audioPlayerPlay.classList.remove("fade-out")
|
||||
audioPlayerPause.classList.add("fade-out")
|
||||
|
||||
if(gainNode) {
|
||||
gainNode.disconnect()
|
||||
}
|
||||
|
||||
if(audioNode) {
|
||||
audioNode.stop()
|
||||
audioNode.disconnect()
|
||||
audioNode = null
|
||||
}
|
||||
// Play or pause audio
|
||||
export function playPauseAudio(arn: AnimeNotifier) {
|
||||
arn.audioPlayer.playPause()
|
||||
}
|
||||
|
||||
// Toggle audio
|
||||
@ -184,86 +51,3 @@ export function toggleAudio(arn: AnimeNotifier, element: HTMLElement) {
|
||||
playAudio(arn, element)
|
||||
}
|
||||
}
|
||||
|
||||
// Play or pause audio
|
||||
export function playPauseAudio(arn: AnimeNotifier) {
|
||||
if(!audioNode) {
|
||||
playNextTrack(arn)
|
||||
return
|
||||
}
|
||||
|
||||
if(audioNode.playbackRate.value === 0) {
|
||||
resumeAudio(arn, audioPlayerPlay)
|
||||
} else {
|
||||
pauseAudio(arn, audioPlayerPlay)
|
||||
}
|
||||
}
|
||||
|
||||
// Play previous track
|
||||
export async function playPreviousTrack(arn: AnimeNotifier) {
|
||||
alert("Previous track is currently work in progress! Check back later :)")
|
||||
}
|
||||
|
||||
// Play next track
|
||||
export async function playNextTrack(arn: AnimeNotifier) {
|
||||
// Get random track
|
||||
let response = await fetch("/api/next/soundtrack")
|
||||
let track = await response.json()
|
||||
|
||||
playAudioFile(arn, track.id, "https://notify.moe/audio/" + track.file)
|
||||
// arn.statusMessage.showInfo("Now playing: " + track.title)
|
||||
|
||||
return track
|
||||
}
|
||||
|
||||
// Set volume
|
||||
export function setVolume(arn: AnimeNotifier, element: HTMLInputElement) {
|
||||
volume = parseFloat(element.value) / 100.0
|
||||
|
||||
if(gainNode) {
|
||||
gainNode.gain.setTargetAtTime(volume, audioContext.currentTime + volumeSmoothingDelay, volumeTimeConstant)
|
||||
}
|
||||
}
|
||||
|
||||
// Pause audio
|
||||
export function pauseAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
if(!audioNode) {
|
||||
return
|
||||
}
|
||||
|
||||
audioNode.playbackRate.setValueAtTime(0.0, 0)
|
||||
|
||||
audioPlayerPlay.classList.remove("fade-out")
|
||||
audioPlayerPause.classList.add("fade-out")
|
||||
}
|
||||
|
||||
// Resume audio
|
||||
export function resumeAudio(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||
if(!audioNode) {
|
||||
playNextTrack(arn)
|
||||
return
|
||||
}
|
||||
|
||||
audioNode.playbackRate.setValueAtTime(targetSpeed, 0)
|
||||
|
||||
audioPlayerPlay.classList.add("fade-out")
|
||||
audioPlayerPause.classList.remove("fade-out")
|
||||
}
|
||||
|
||||
// Add speed
|
||||
export function addSpeed(arn: AnimeNotifier, speed: number) {
|
||||
if(!audioNode || audioNode.playbackRate.value === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
targetSpeed += speed
|
||||
|
||||
if(targetSpeed < 0.5) {
|
||||
targetSpeed = 0.5
|
||||
} else if(targetSpeed > 2) {
|
||||
targetSpeed = 2
|
||||
}
|
||||
|
||||
audioNode.playbackRate.setValueAtTime(targetSpeed, 0)
|
||||
arn.statusMessage.showInfo("Playback speed: " + Math.round(targetSpeed * 100) + "%")
|
||||
}
|
@ -4,6 +4,7 @@ import { StatusMessage } from "./StatusMessage"
|
||||
import { PushManager } from "./PushManager"
|
||||
import { TouchController } from "./TouchController"
|
||||
import { NotificationManager } from "./NotificationManager"
|
||||
import { AudioPlayer } from "./AudioPlayer"
|
||||
import { Analytics } from "./Analytics"
|
||||
import { SideBar } from "./SideBar"
|
||||
import { InfiniteScroller } from "./InfiniteScroller"
|
||||
@ -11,8 +12,6 @@ import { ServiceWorkerManager } from "./ServiceWorkerManager"
|
||||
import { displayAiringDate, displayDate, displayTime } from "./DateView"
|
||||
import { findAll, delay, canUseWebP, swapElements } from "./Utils"
|
||||
import * as actions from "./Actions"
|
||||
import { darkTheme, addSpeed, playPreviousTrack, search } from "./Actions";
|
||||
import { playPauseAudio, playNextTrack } from "./Actions/Audio"
|
||||
|
||||
export class AnimeNotifier {
|
||||
app: Application
|
||||
@ -27,6 +26,7 @@ export class AnimeNotifier {
|
||||
serviceWorkerManager: ServiceWorkerManager
|
||||
notificationManager: NotificationManager
|
||||
touchController: TouchController
|
||||
audioPlayer: AudioPlayer
|
||||
sideBar: SideBar
|
||||
infiniteScroller: InfiniteScroller
|
||||
mainPageLoaded: boolean
|
||||
@ -116,7 +116,7 @@ export class AnimeNotifier {
|
||||
|
||||
// Theme
|
||||
if(this.user && this.user.dataset.pro === "true" && this.user.dataset.theme !== "light") {
|
||||
darkTheme(this)
|
||||
actions.darkTheme(this)
|
||||
}
|
||||
|
||||
// Status message
|
||||
@ -131,6 +131,9 @@ export class AnimeNotifier {
|
||||
// Notification manager
|
||||
this.notificationManager = new NotificationManager()
|
||||
|
||||
// Audio player
|
||||
this.audioPlayer = new AudioPlayer(this)
|
||||
|
||||
// Analytics
|
||||
this.analytics = new Analytics()
|
||||
|
||||
@ -877,7 +880,7 @@ export class AnimeNotifier {
|
||||
case "INPUT":
|
||||
//
|
||||
if(activeElement.id === "search" && e.keyCode === 13) {
|
||||
search(this, activeElement as HTMLInputElement, e)
|
||||
actions.search(this, activeElement as HTMLInputElement, e)
|
||||
}
|
||||
|
||||
return
|
||||
@ -938,7 +941,7 @@ export class AnimeNotifier {
|
||||
|
||||
// "+" = Audio speed up
|
||||
if(e.keyCode === 107 || e.keyCode === 187) {
|
||||
addSpeed(this, 0.05)
|
||||
this.audioPlayer.addSpeed(0.05)
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@ -947,7 +950,7 @@ export class AnimeNotifier {
|
||||
|
||||
// "-" = Audio speed down
|
||||
if(e.keyCode === 109 || e.keyCode === 189) {
|
||||
addSpeed(this, -0.05)
|
||||
this.audioPlayer.addSpeed(-0.05)
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@ -956,7 +959,7 @@ export class AnimeNotifier {
|
||||
|
||||
// "J" = Previous track
|
||||
if(e.keyCode === 74) {
|
||||
playPreviousTrack(this)
|
||||
this.audioPlayer.previous()
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@ -965,7 +968,7 @@ export class AnimeNotifier {
|
||||
|
||||
// "K" = Play/pause
|
||||
if(e.keyCode === 75) {
|
||||
playPauseAudio(this)
|
||||
this.audioPlayer.playPause()
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@ -974,7 +977,7 @@ export class AnimeNotifier {
|
||||
|
||||
// "L" = Next track
|
||||
if(e.keyCode === 76) {
|
||||
playNextTrack(this)
|
||||
this.audioPlayer.next()
|
||||
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
274
scripts/AudioPlayer.ts
Normal file
274
scripts/AudioPlayer.ts
Normal file
@ -0,0 +1,274 @@
|
||||
import { AnimeNotifier } from "./AnimeNotifier"
|
||||
|
||||
export class AudioPlayer {
|
||||
arn: AnimeNotifier
|
||||
|
||||
// Web audio
|
||||
audioContext: AudioContext
|
||||
audioNode: AudioBufferSourceNode
|
||||
gainNode: GainNode
|
||||
|
||||
// Parameters
|
||||
volume = 0.5
|
||||
volumeTimeConstant = 0.01
|
||||
volumeSmoothingDelay = 0.05
|
||||
targetSpeed = 1.0
|
||||
playId = 0
|
||||
|
||||
// Save last request so that we can cancel it
|
||||
lastRequest: XMLHttpRequest
|
||||
|
||||
// DOM elements
|
||||
audioPlayer: HTMLElement
|
||||
audioPlayerPlay: HTMLButtonElement
|
||||
audioPlayerPause: HTMLButtonElement
|
||||
trackLink: HTMLLinkElement
|
||||
animeInfo: HTMLElement
|
||||
animeLink: HTMLLinkElement
|
||||
animeImage: HTMLImageElement
|
||||
|
||||
constructor(arn: AnimeNotifier) {
|
||||
this.arn = arn
|
||||
this.audioPlayer = document.getElementById("audio-player")
|
||||
this.audioPlayerPlay = document.getElementById("audio-player-play") as HTMLButtonElement
|
||||
this.audioPlayerPause = document.getElementById("audio-player-pause") as HTMLButtonElement
|
||||
this.trackLink = document.getElementById("audio-player-track-title") as HTMLLinkElement
|
||||
this.animeInfo = document.getElementById("audio-player-anime-info") as HTMLElement
|
||||
this.animeLink = document.getElementById("audio-player-anime-link") as HTMLLinkElement
|
||||
this.animeImage = document.getElementById("audio-player-anime-image") as HTMLImageElement
|
||||
}
|
||||
|
||||
// Play audio file
|
||||
play(trackId: string, trackUrl: string) {
|
||||
if(!this.audioContext) {
|
||||
this.audioContext = new AudioContext()
|
||||
this.gainNode = this.audioContext.createGain()
|
||||
this.gainNode.gain.setTargetAtTime(this.volume, this.audioContext.currentTime + this.volumeSmoothingDelay, this.volumeTimeConstant)
|
||||
}
|
||||
|
||||
this.playId++
|
||||
let currentPlayId = this.playId
|
||||
|
||||
if(this.lastRequest) {
|
||||
this.lastRequest.abort()
|
||||
this.lastRequest = null
|
||||
}
|
||||
|
||||
// Stop current track
|
||||
this.stop()
|
||||
|
||||
this.arn.currentSoundTrackId = trackId
|
||||
this.arn.markPlayingSoundTrack()
|
||||
this.arn.loading(true)
|
||||
|
||||
// Mark as loading
|
||||
this.audioPlayer.classList.add("loading-network")
|
||||
this.audioPlayer.classList.remove("decoding-audio")
|
||||
this.audioPlayer.classList.remove("decoded")
|
||||
|
||||
// Request
|
||||
let request = new XMLHttpRequest()
|
||||
request.open("GET", trackUrl, true)
|
||||
request.responseType = "arraybuffer"
|
||||
|
||||
request.onload = () => {
|
||||
if(currentPlayId !== this.playId) {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark as loading finished, now decoding starts
|
||||
this.audioPlayer.classList.add("decoding-audio")
|
||||
this.arn.loading(false)
|
||||
|
||||
this.audioContext.decodeAudioData(request.response, async buffer => {
|
||||
if(currentPlayId !== this.playId) {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark as ready
|
||||
this.audioPlayer.classList.add("decoded")
|
||||
|
||||
this.audioNode = this.audioContext.createBufferSource()
|
||||
this.audioNode.buffer = buffer
|
||||
this.audioNode.connect(this.gainNode)
|
||||
this.gainNode.connect(this.audioContext.destination)
|
||||
this.audioNode.playbackRate.setValueAtTime(this.targetSpeed, 0)
|
||||
this.audioNode.start(0)
|
||||
|
||||
this.audioNode.onended = (event: MediaStreamErrorEvent) => {
|
||||
if(currentPlayId !== this.playId) {
|
||||
return
|
||||
}
|
||||
|
||||
this.next()
|
||||
}
|
||||
}, console.error)
|
||||
}
|
||||
|
||||
request.onerror = () => {
|
||||
this.arn.loading(false)
|
||||
}
|
||||
|
||||
this.lastRequest = request
|
||||
request.send()
|
||||
|
||||
// Update track info
|
||||
this.updateTrackInfo(trackId)
|
||||
|
||||
// Show audio player
|
||||
this.audioPlayer.classList.remove("fade-out")
|
||||
this.audioPlayerPlay.classList.add("fade-out")
|
||||
this.audioPlayerPause.classList.remove("fade-out")
|
||||
}
|
||||
|
||||
// Pause
|
||||
pause() {
|
||||
if(!this.audioNode) {
|
||||
return
|
||||
}
|
||||
|
||||
this.audioNode.playbackRate.setValueAtTime(0.0, 0)
|
||||
|
||||
this.audioPlayerPlay.classList.remove("fade-out")
|
||||
this.audioPlayerPause.classList.add("fade-out")
|
||||
}
|
||||
|
||||
// Resume
|
||||
resume() {
|
||||
if(!this.audioNode) {
|
||||
this.next()
|
||||
return
|
||||
}
|
||||
|
||||
this.audioNode.playbackRate.setValueAtTime(this.targetSpeed, 0)
|
||||
|
||||
this.audioPlayerPlay.classList.add("fade-out")
|
||||
this.audioPlayerPause.classList.remove("fade-out")
|
||||
}
|
||||
|
||||
// Stop
|
||||
stop() {
|
||||
this.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")
|
||||
|
||||
// Remove title
|
||||
this.trackLink.href = ""
|
||||
this.trackLink.innerText = ""
|
||||
|
||||
// Hide anime info
|
||||
this.animeLink.href = ""
|
||||
this.animeInfo.classList.add("hidden")
|
||||
this.animeImage.classList.add("hidden")
|
||||
|
||||
// Show play button
|
||||
this.audioPlayerPlay.classList.remove("fade-out")
|
||||
this.audioPlayerPause.classList.add("fade-out")
|
||||
|
||||
if(this.gainNode) {
|
||||
this.gainNode.disconnect()
|
||||
}
|
||||
|
||||
if(this.audioNode) {
|
||||
this.audioNode.stop()
|
||||
this.audioNode.disconnect()
|
||||
this.audioNode = null
|
||||
}
|
||||
}
|
||||
|
||||
// Previous track
|
||||
async previous() {
|
||||
alert("Previous track is currently work in progress! Check back later :)")
|
||||
}
|
||||
|
||||
// Next track
|
||||
async next() {
|
||||
// Get random track
|
||||
let response = await fetch("/api/next/soundtrack")
|
||||
let track = await response.json()
|
||||
|
||||
this.play(track.id, "https://notify.moe/audio/" + track.file)
|
||||
// arn.statusMessage.showInfo("Now playing: " + track.title)
|
||||
|
||||
return track
|
||||
}
|
||||
|
||||
// Set volume
|
||||
setVolume(volume: number) {
|
||||
if(!this.gainNode) {
|
||||
return
|
||||
}
|
||||
|
||||
this.gainNode.gain.setTargetAtTime(volume, this.audioContext.currentTime + this.volumeSmoothingDelay, this.volumeTimeConstant)
|
||||
}
|
||||
|
||||
// Add speed
|
||||
addSpeed(speed: number) {
|
||||
if(!this.audioNode || this.audioNode.playbackRate.value === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
this.targetSpeed += speed
|
||||
|
||||
if(this.targetSpeed < 0.5) {
|
||||
this.targetSpeed = 0.5
|
||||
} else if(this.targetSpeed > 2) {
|
||||
this.targetSpeed = 2
|
||||
}
|
||||
|
||||
this.audioNode.playbackRate.setValueAtTime(this.targetSpeed, 0)
|
||||
this.arn.statusMessage.showInfo("Playback speed: " + Math.round(this.targetSpeed * 100) + "%")
|
||||
}
|
||||
|
||||
// Play or pause
|
||||
playPause() {
|
||||
if(!this.audioNode) {
|
||||
this.next()
|
||||
return
|
||||
}
|
||||
|
||||
if(this.audioNode.playbackRate.value === 0) {
|
||||
this.resume()
|
||||
} else {
|
||||
this.pause()
|
||||
}
|
||||
}
|
||||
|
||||
// Update track info
|
||||
async updateTrackInfo(trackId: string) {
|
||||
// Set track title
|
||||
let trackInfoResponse = await fetch("/api/soundtrack/" + trackId)
|
||||
let track = await trackInfoResponse.json()
|
||||
this.trackLink.href = "/soundtrack/" + track.id
|
||||
this.trackLink.innerText = track.title
|
||||
|
||||
let animeId = ""
|
||||
|
||||
for(let tag of (track.tags as string[])) {
|
||||
if(tag.startsWith("anime:")) {
|
||||
animeId = tag.split(":")[1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set anime info
|
||||
if(animeId !== "") {
|
||||
this.animeInfo.classList.remove("hidden")
|
||||
let animeResponse = await fetch("/api/anime/" + animeId)
|
||||
let anime = await animeResponse.json()
|
||||
this.animeLink.title = anime.title.canonical
|
||||
this.animeLink.href = "/anime/" + anime.id
|
||||
this.animeImage.dataset.src = "//media.notify.moe/images/anime/medium/" + anime.id + ".jpg"
|
||||
this.animeImage.classList.remove("hidden")
|
||||
this.animeImage["became visible"]()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user