web2img/assets/js/tmpl.js
2021-09-05 17:58:19 +08:00

242 lines
5.6 KiB
JavaScript

function pageEnv() {
var container = document.documentElement
function showErr(msg) {
container.innerHTML = msg
}
function reload() {
location.reload()
}
var currentScript = document.currentScript
var jsUrl = currentScript.src
var rootPath
if (jsUrl) {
var sw = navigator.serviceWorker
if (!sw) {
showErr('Error: Service Worker is not supported')
return
}
var swPending = sw.register(jsUrl).catch(function(err) {
showErr(err.message)
})
rootPath = getRootPath(jsUrl)
} else {
rootPath = currentScript.dataset.root
}
function parseImgBuf(buf) {
if (!buf) {
loadNextUrl()
return
}
crypto.subtle.digest('SHA-256', buf).then(function(digest) {
var hashBin = new Uint8Array(digest)
var hashB64 = btoa(String.fromCharCode.apply(null, hashBin))
if (typeof HASH !== 'undefined' && HASH !== hashB64) {
loadNextUrl()
return
}
var bytes = decode1Px3Bytes(buf)
caches.delete('.web2img').then(function() {
caches.open('.web2img').then(function(cache) {
unpack(bytes, cache).then(function() {
if (swPending) {
swPending.then(reload)
} else {
reload()
}
})
})
})
})
}
// run in iframe
var loadImg = function(e) {
var img = new Image()
img.onload = function() {
var canvas = document.createElement('canvas')
canvas.width = img.width
canvas.height = img.height
var ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0)
var imgData = ctx.getImageData(0, 0, img.width, img.height)
var buf = imgData.data.buffer
// inline
if (typeof PRIVACY === 'undefined' || PRIVACY === 2) {
parent.postMessage(buf, '*', [buf])
} else {
parseImgBuf(buf)
}
}
img.onerror = function() {
if (typeof PRIVACY === 'undefined' || PRIVACY === 2) {
parent.postMessage('', '*')
} else {
parseImgBuf()
}
}
if (typeof PRIVACY !== 'undefined' && PRIVACY === 1) {
img.referrerPolicy = 'no-referrer'
}
img.crossOrigin = 1
img.src = e.data
}
if (PRIVACY === 2) {
// hide origin header
var iframe = document.createElement('iframe')
if (typeof RELEASE !== 'undefined') {
iframe.src = 'data:text/html,<script>onmessage=' + loadImg + '</script>'
} else {
iframe.src = 'data:text/html;base64,' + btoa('<script>onmessage=' + loadImg + '</script>')
}
iframe.style.display = 'none'
iframe.onload = loadNextUrl
container.appendChild(iframe)
var iframeWin = iframe.contentWindow
self.onmessage = function(e) {
if (e.source === iframeWin) {
parseImgBuf(e.data)
}
}
} else {
loadNextUrl()
}
function loadNextUrl() {
var url = URLS.shift()
if (!url) {
return
}
if (PRIVACY === 2) {
iframeWin.postMessage(url, '*')
} else {
loadImg({data: url})
}
}
function decode1Px3Bytes(pixelBuf) {
var u32 = new Uint32Array(pixelBuf)
var out = new Uint8Array(u32.length * 3)
var p = 0
u32.forEach(function(rgba) {
out[p++] = rgba
out[p++] = rgba >> 8
out[p++] = rgba >> 16
})
return out
}
function unpack(bytes, cache) {
var confEnd = bytes.indexOf(13) // '\r'
var confBin = bytes.subarray(0, confEnd)
var confStr = new TextDecoder().decode(confBin)
var confObj = JSON.parse(confStr)
var offset = confEnd + 1
var pendings = []
for (var file in confObj) {
var headers = confObj[file]
headers['cache-control'] = 'max-age=60'
var len = headers['content-length']
var bin = bytes.subarray(offset, offset + len)
var req = new Request(rootPath + file)
var res = new Response(bin, {
headers: headers
})
pendings.push(
cache.put(req, res)
)
offset += len
}
return Promise.all(pendings)
}
}
function swEnv() {
var jsUrl = location.href
var rootPath = getRootPath(jsUrl)
var hasUpdate
var currJs
// check update
setInterval(function() {
var p = 'cache' in Request.prototype
? fetch(jsUrl, {cache: 'no-cache'})
: fetch(jsUrl + '?t=' + Date.now())
p.then(function(res) {
res.text().then(function(js) {
if (currJs !== js) {
if (currJs) {
hasUpdate = 1
console.log('update')
}
currJs = js
}
})
})
}, 1000 * 120)
onfetch = function(e) {
var req = e.request
if (req.url.indexOf(rootPath)) {
// url not starts with rootPath
return
}
var res
if (hasUpdate && req.mode === 'navigate') {
var html = '<script data-root="' + rootPath + '">' + currJs + '</script>'
res = new Response(html, {
headers: {
'content-type': 'text/html'
}
})
hasUpdate = 0
} else {
var path = new URL(req.url).pathname
.replace(/\/{2,}/g, '/')
.replace(/\/$/, '/index.html')
res = caches.open('.web2img').then(function(cache) {
return cache.match(path).then(function(res) {
return res || cache.match(rootPath + '404.html').then(function(res) {
return res || new Response('file not found: ' + path, {
status: 404
})
})
})
})
}
e.respondWith(res)
}
}
function getRootPath(url) {
// e.g.
// 'https://mysite.com/'
// 'https://xx.github.io/path/to/'
return url.split('?')[0].replace(/[^/]+$/, '')
}
if (self.document) {
pageEnv()
} else {
swEnv()
}