<commit_before>import AnimeNotifier from "../AnimeNotifier"
import StatusMessage from "../StatusMessage"
import { bytesHumanReadable, uploadWithProgress } from "../Utils"

// Select file
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
	if(button.dataset.endpoint === "/api/upload/cover" && arn.user.dataset.pro !== "true") {
		alert("Please buy a PRO account to use this feature.")
		return
	}

	let fileType = button.dataset.type
	let endpoint = button.dataset.endpoint

	// Click on virtual file input element
	let input = document.createElement("input")
	input.setAttribute("type", "file")

	input.onchange = () => {
		let file = input.files[0]

		if(!file) {
			return
		}

		// Check mime type for images
		if(fileType === "image" && !file.type.startsWith("image/")) {
			arn.statusMessage.showError(file.name + " is not an image file!")
			return
		}

		// Check mime type for videos
		if(fileType === "video" && !file.type.startsWith("video/webm")) {
			arn.statusMessage.showError(file.name + " is not a WebM video file!")
			return
		}

		// Preview image
		if(fileType === "image") {
			let previews = document.getElementsByClassName(button.id + "-preview")

			for(let preview of previews) {
				previewImage(file, endpoint, previews)
			}
		}

		uploadFile(file, fileType, endpoint, arn)
	}

	input.click()
}

// Upload file
function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNotifier) {
	let reader = new FileReader()

	reader.onloadend = async () => {
		let fileSize = reader.result.byteLength

		if(fileSize === 0) {
			arn.statusMessage.showError("File is empty")
			return
		}

		arn.statusMessage.showInfo(`Preparing to upload ${fileType} (${bytesHumanReadable(fileSize)})`, -1)

		try {
			let responseText = await uploadWithProgress(endpoint, {
				method: "POST",
				credentials: "include",
				headers: {
					"Content-Type": "application/octet-stream"
				},
				body: reader.result
			}, e => {
				let progress = e.loaded / (e.lengthComputable ? e.total : fileSize) * 100
				arn.statusMessage.showInfo(`Uploading ${fileType}...${progress.toFixed(1)}%`, -1)
			})

			arn.statusMessage.showInfo(`Successfully uploaded your new ${fileType}.`)

			if(endpoint === "/api/upload/avatar") {
				// We received the new avatar URL
				updateSideBarAvatar(responseText)
			}
		} catch(err) {
			arn.statusMessage.showError(`Failed uploading your new ${fileType}.`)
			console.error(err)
		}
	}

	arn.statusMessage.showInfo(`Reading ${fileType} from disk...`, -1)
	reader.readAsArrayBuffer(file)
}

// Preview image
function previewImage(file: File, endpoint: string, previews: HTMLCollectionOf<Element>) {
	let reader = new FileReader()

	reader.onloadend = () => {
		if(endpoint === "/api/upload/avatar") {
			let svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement

			if(svgPreview) {
				svgPreview.classList.add("hidden")
			}
		}

		for(let preview of previews) {
			let img = preview as HTMLImageElement
			img.classList.remove("hidden")
			img.classList.remove("element-not-found")
			img.src = reader.result
		}
	}

	reader.readAsDataURL(file)
}

// Update sidebar avatar
function updateSideBarAvatar(url: string) {
	let sidebar = document.getElementById("sidebar")
	let userImage = sidebar.getElementsByClassName("user-image")[0] as HTMLImageElement
	let lazyLoad = userImage["became visible"]

	if(lazyLoad) {
		userImage.dataset.src = url
		lazyLoad()
	} else {
		location.reload()
	}
}<commit_msg>Fixed image upload for missing images<commit_after>import AnimeNotifier from "../AnimeNotifier"
import StatusMessage from "../StatusMessage"
import { bytesHumanReadable, uploadWithProgress } from "../Utils"

// Select file
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
	if(button.dataset.endpoint === "/api/upload/cover" && arn.user.dataset.pro !== "true") {
		alert("Please buy a PRO account to use this feature.")
		return
	}

	let fileType = button.dataset.type
	let endpoint = button.dataset.endpoint

	// Click on virtual file input element
	let input = document.createElement("input")
	input.setAttribute("type", "file")

	input.onchange = () => {
		let file = input.files[0]

		if(!file) {
			return
		}

		// Check mime type for images
		if(fileType === "image" && !file.type.startsWith("image/")) {
			arn.statusMessage.showError(file.name + " is not an image file!")
			return
		}

		// Check mime type for videos
		if(fileType === "video" && !file.type.startsWith("video/webm")) {
			arn.statusMessage.showError(file.name + " is not a WebM video file!")
			return
		}

		// Preview image
		if(fileType === "image") {
			let previews = document.getElementsByClassName(button.id + "-preview")

			for(let preview of previews) {
				previewImage(file, endpoint, previews)
			}
		}

		uploadFile(file, fileType, endpoint, arn)
	}

	input.click()
}

// Upload file
function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNotifier) {
	let reader = new FileReader()

	reader.onloadend = async () => {
		let fileSize = reader.result.byteLength

		if(fileSize === 0) {
			arn.statusMessage.showError("File is empty")
			return
		}

		arn.statusMessage.showInfo(`Preparing to upload ${fileType} (${bytesHumanReadable(fileSize)})`, -1)

		try {
			let responseText = await uploadWithProgress(endpoint, {
				method: "POST",
				credentials: "include",
				headers: {
					"Content-Type": "application/octet-stream"
				},
				body: reader.result
			}, e => {
				let progress = e.loaded / (e.lengthComputable ? e.total : fileSize) * 100
				arn.statusMessage.showInfo(`Uploading ${fileType}...${progress.toFixed(1)}%`, -1)
			})

			arn.statusMessage.showInfo(`Successfully uploaded your new ${fileType}.`)

			if(endpoint === "/api/upload/avatar") {
				// We received the new avatar URL
				updateSideBarAvatar(responseText)
			}
		} catch(err) {
			arn.statusMessage.showError(`Failed uploading your new ${fileType}.`)
			console.error(err)
		}
	}

	arn.statusMessage.showInfo(`Reading ${fileType} from disk...`, -1)
	reader.readAsArrayBuffer(file)
}

// Preview image
function previewImage(file: File, endpoint: string, previews: HTMLCollectionOf<Element>) {
	let reader = new FileReader()

	reader.onloadend = () => {
		if(endpoint === "/api/upload/avatar") {
			let svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement

			if(svgPreview) {
				svgPreview.classList.add("hidden")
			}
		}

		for(let preview of previews) {
			let img = preview as HTMLImageElement
			img.classList.remove("hidden")

			// Make not found images visible again
			if(img.classList.contains("lazy")) {
				img.classList.remove("element-not-found")
				img.classList.add("element-found")
			}

			img.src = reader.result
		}
	}

	reader.readAsDataURL(file)
}

// Update sidebar avatar
function updateSideBarAvatar(url: string) {
	let sidebar = document.getElementById("sidebar")
	let userImage = sidebar.getElementsByClassName("user-image")[0] as HTMLImageElement
	let lazyLoad = userImage["became visible"]

	if(lazyLoad) {
		userImage.dataset.src = url
		lazyLoad()
	} else {
		location.reload()
	}
}
{'fraction_non_alphanumeric': 0.14154488517745303, 'fraction_numerical': 0.0027835768963117608, 'mean_word_length': 3.861975642760487, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 13, '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': '4791453', 'n_tokens_mistral': 2576, 'n_tokens_neox': 2268, 'n_words': 521}