<commit_before>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)
}

// 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")
}

// 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 + anime.imageExtension
		animeImage.classList.remove("hidden")
		animeImage["became visible"]()
	}
}
<commit_msg>Fixed media player images<commit_after>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)
}

// 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")
}

// 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"]()
	}
}

{'fraction_non_alphanumeric': 0.12144904873599166, 'fraction_numerical': 0.0036486838676048996, 'mean_word_length': 4.643382352941177, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7625842', 'n_tokens_mistral': 2575, 'n_tokens_neox': 2402, 'n_words': 493}