4chan-XZ/src/Images/ImageCommon.ts
2023-05-05 04:15:53 +02:00

150 lines
4.7 KiB
TypeScript

import Redirect from "../Archive/Redirect"
import Notice from "../classes/Notice"
import { Conf, d, g } from "../globals/globals"
import $ from "../platform/$"
import CrossOrigin from "../platform/CrossOrigin"
import { dict } from "../platform/helpers"
import ImageHost from "./ImageHost"
import Volume from "./Volume"
const ImageCommon = {
cache: null,
// Pause and mute video in preparation for removing the element from the document.
pause(video) {
if (video.nodeName !== 'VIDEO') { return }
video.pause()
$.off(video, 'volumechange', Volume.change)
return video.muted = true
},
rewind(el) {
if (el.nodeName === 'VIDEO') {
if (el.readyState >= el.HAVE_METADATA) { return el.currentTime = 0 }
} else if (/\.gif$/.test(el.src)) {
return $.queueTask(() => el.src = el.src)
}
},
pushCache(el) {
ImageCommon.cache = el
return $.on(el, 'error', ImageCommon.cacheError)
},
popCache() {
const el = ImageCommon.cache
$.off(el, 'error', ImageCommon.cacheError)
delete ImageCommon.cache
return el
},
cacheError() {
if (ImageCommon.cache === this) { return delete ImageCommon.cache }
},
decodeError(file, fileObj) {
let message
if (file.error?.code !== MediaError.MEDIA_ERR_DECODE) { return false }
if (!(message = $('.warning', fileObj.thumb.parentNode))) {
message = $.el('div', { className: 'warning' })
$.after(fileObj.thumb, message)
}
message.textContent = 'Error: Corrupt or unplayable video'
return true
},
isFromArchive(file) {
return (g.SITE.software === 'yotsuba') && !ImageHost.test(file.src.split('/')[2])
},
error(file, post, fileObj, delay, cb) {
let timeoutID
const src = fileObj.url.split('/')
let url = null
if ((g.SITE.software === 'yotsuba') && Conf['404 Redirect']) {
url = Redirect.to('file', {
boardID: post.board.ID,
filename: src[src.length - 1]
})
}
if (!url || !Redirect.securityCheck(url)) { url = null }
if ((post.isDead || fileObj.isDead) && !ImageCommon.isFromArchive(file)) { return cb(url) }
if (delay != null) { timeoutID = setTimeout((() => cb(url)), delay) }
if (post.isDead || fileObj.isDead) { return }
const redirect = function () {
if (!ImageCommon.isFromArchive(file)) {
if (delay != null) { clearTimeout(timeoutID) }
return cb(url)
}
}
const threadJSON = g.SITE.urls.threadJSON?.(post)
if (!threadJSON) { return }
const parseJSON = function (isArchiveURL) {
let needle, postObj
if (this.status === 404) {
let archivedThreadJSON
if (!isArchiveURL && (archivedThreadJSON = g.SITE.urls.archivedThreadJSON?.(post))) {
$.ajax(archivedThreadJSON, { onloadend() { return parseJSON.call(this, true) } })
} else {
post.kill(!post.isClone, fileObj.index)
}
}
if (this.status !== 200) { return redirect() }
for (postObj of this.response.posts) {
if (postObj.no === post.ID) { break }
}
if (postObj.no !== post.ID) {
post.kill()
return redirect()
} else if ((needle = fileObj.docIndex, g.SITE.Build.parseJSON(postObj, post.board).filesDeleted.includes(needle))) {
post.kill(true)
return redirect()
} else {
return url = fileObj.url
}
}
return $.ajax(threadJSON, { onloadend() { return parseJSON.call(this) } })
},
// Add controls, but not until the mouse is moved over the video.
addControls(video) {
const handler = function () {
$.off(video, 'mouseover', handler)
// Hacky workaround for Firefox forever-loading bug for very short videos
const t = new Date().getTime()
return $.asap((() => ($.engine !== 'gecko') || ((video.readyState >= 3) && (video.currentTime <= Math.max(0.1, (video.duration - 0.5)))) || (new Date().getTime() >= (t + 1000))), () => video.controls = true)
}
return $.on(video, 'mouseover', handler)
},
// XXX Estimate whether clicks are on the video controls and should be ignored.
onControls(e) {
return (Conf['Show Controls'] && Conf['Click Passthrough'] && (e.target.nodeName === 'VIDEO')) ||
(e.target.controls && ((e.target.getBoundingClientRect().bottom - e.clientY) < 35))
},
download(e) {
if (this.protocol === 'blob:') { return true }
e.preventDefault()
const { href, download } = this
return CrossOrigin.file(href, function (blob) {
if (blob) {
const a = $.el('a', {
href: URL.createObjectURL(blob),
download,
hidden: true
}
)
$.add(d.body, a)
a.click()
return $.rm(a)
} else {
return new Notice('warning', `Could not download ${href}`, 20)
}
})
}
}
export default ImageCommon