2021-09-05 09:58:19 +00:00
|
|
|
function pageEnv() {
|
|
|
|
var container = document.documentElement
|
|
|
|
|
2021-09-09 08:25:40 +00:00
|
|
|
function fallback(html) {
|
2021-09-09 15:56:47 +00:00
|
|
|
var noscripts = document.getElementsByTagName('noscript')
|
|
|
|
if (noscripts.length > 0) {
|
|
|
|
html = noscripts[0].innerHTML
|
2021-09-09 08:25:40 +00:00
|
|
|
}
|
|
|
|
container.innerHTML = html
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
|
2021-09-18 03:04:23 +00:00
|
|
|
var jsUrl = document.currentScript.src
|
|
|
|
var sw = navigator.serviceWorker
|
|
|
|
if (!sw) {
|
|
|
|
fallback('Service Worker is not supported')
|
|
|
|
return
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
2021-09-18 03:04:23 +00:00
|
|
|
var rootPath = getRootPath(jsUrl)
|
|
|
|
|
2021-09-05 09:58:19 +00:00
|
|
|
|
2021-09-09 15:56:47 +00:00
|
|
|
function unpackToCache(bytes, cache) {
|
2021-09-18 03:04:23 +00:00
|
|
|
var pendings = []
|
|
|
|
|
|
|
|
if (!sw.controller) {
|
|
|
|
var swPending = sw.register(jsUrl).catch(function(err) {
|
|
|
|
fallback(err.message)
|
|
|
|
})
|
|
|
|
pendings.push(swPending)
|
|
|
|
}
|
|
|
|
|
2021-09-09 15:56:47 +00:00
|
|
|
var info = JSON.stringify({
|
|
|
|
hash: HASH,
|
|
|
|
time: Date.now()
|
|
|
|
})
|
|
|
|
var res = new Response(info)
|
2021-12-17 08:19:35 +00:00
|
|
|
pendings.push(
|
2021-09-09 15:56:47 +00:00
|
|
|
cache.put(rootPath + '.cache-info', res),
|
2021-12-17 08:19:35 +00:00
|
|
|
)
|
2021-09-18 03:04:23 +00:00
|
|
|
|
2021-09-09 15:56:47 +00:00
|
|
|
var pathResMap = unpack(bytes)
|
|
|
|
|
|
|
|
for (var path in pathResMap) {
|
|
|
|
res = pathResMap[path]
|
|
|
|
pendings.push(
|
|
|
|
cache.put(rootPath + path, res)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
Promise.all(pendings).then(function() {
|
|
|
|
location.reload()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-05 09:58:19 +00:00
|
|
|
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))
|
2021-09-10 08:03:06 +00:00
|
|
|
if (HASH && HASH !== hashB64) {
|
|
|
|
console.warn('[web2img] bad hash. exp:', HASH, 'but got:', hashB64)
|
2021-09-05 09:58:19 +00:00
|
|
|
loadNextUrl()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var bytes = decode1Px3Bytes(buf)
|
|
|
|
caches.delete('.web2img').then(function() {
|
|
|
|
caches.open('.web2img').then(function(cache) {
|
2021-09-09 15:56:47 +00:00
|
|
|
unpackToCache(bytes, cache)
|
2021-09-05 09:58:19 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// run in iframe
|
|
|
|
var loadImg = function(e) {
|
2021-09-10 08:03:06 +00:00
|
|
|
var opt = e.data
|
2021-09-05 09:58:19 +00:00
|
|
|
var img = new Image()
|
|
|
|
|
|
|
|
img.onload = function() {
|
2021-09-10 08:03:06 +00:00
|
|
|
clearInterval(tid)
|
|
|
|
|
2021-09-05 09:58:19 +00:00
|
|
|
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
|
|
|
|
|
2021-09-10 08:03:06 +00:00
|
|
|
if (opt.privacy === 2) {
|
2021-09-05 09:58:19 +00:00
|
|
|
parent.postMessage(buf, '*', [buf])
|
|
|
|
} else {
|
|
|
|
parseImgBuf(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
img.onerror = function() {
|
2021-09-10 08:03:06 +00:00
|
|
|
clearInterval(tid)
|
|
|
|
|
|
|
|
if (opt.privacy === 2) {
|
2021-09-05 09:58:19 +00:00
|
|
|
parent.postMessage('', '*')
|
|
|
|
} else {
|
|
|
|
parseImgBuf()
|
|
|
|
}
|
|
|
|
}
|
2021-09-10 08:03:06 +00:00
|
|
|
if (opt.privacy === 1) {
|
2021-09-05 09:58:19 +00:00
|
|
|
img.referrerPolicy = 'no-referrer'
|
|
|
|
}
|
|
|
|
img.crossOrigin = 1
|
2021-09-10 08:03:06 +00:00
|
|
|
img.src = opt.url
|
|
|
|
|
|
|
|
var tid = setTimeout(function() {
|
|
|
|
console.log('[web2img] timeout:', opt.url)
|
|
|
|
img.onerror()
|
|
|
|
img.onerror = img.onload = null
|
|
|
|
img.src = ''
|
|
|
|
}, opt.timeout)
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (PRIVACY === 2) {
|
2021-09-09 15:56:47 +00:00
|
|
|
// hide `origin` header
|
2021-09-05 09:58:19 +00:00
|
|
|
var iframe = document.createElement('iframe')
|
|
|
|
|
|
|
|
if (typeof RELEASE !== 'undefined') {
|
2021-09-18 03:04:23 +00:00
|
|
|
iframe.src = 'data:text/html,<script>onmessage=' + loadImg + '</script>'
|
2021-09-05 09:58:19 +00:00
|
|
|
} else {
|
2021-09-18 03:04:23 +00:00
|
|
|
iframe.src = 'data:text/html;base64,' + btoa('<script>onmessage=' + loadImg + '</script>')
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
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) {
|
2021-09-09 08:25:40 +00:00
|
|
|
fallback('failed to load resources')
|
2021-09-05 09:58:19 +00:00
|
|
|
return
|
|
|
|
}
|
2021-09-10 08:03:06 +00:00
|
|
|
var opt = {
|
|
|
|
url: url,
|
|
|
|
privacy: PRIVACY,
|
|
|
|
timeout: IMG_TIMEOUT * 1000
|
|
|
|
}
|
2021-09-05 09:58:19 +00:00
|
|
|
if (PRIVACY === 2) {
|
2021-09-10 08:03:06 +00:00
|
|
|
iframeWin.postMessage(opt, '*')
|
2021-09-05 09:58:19 +00:00
|
|
|
} else {
|
2021-09-10 08:03:06 +00:00
|
|
|
loadImg({data: opt})
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-09-09 15:56:47 +00:00
|
|
|
function unpack(bytes) {
|
2021-09-05 09:58:19 +00:00
|
|
|
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
|
|
|
|
|
2021-09-09 15:56:47 +00:00
|
|
|
for (var path in confObj) {
|
|
|
|
var headers = confObj[path]
|
2021-09-10 08:03:06 +00:00
|
|
|
var expires = /\.html$/.test(path) ? 5 : UPDATE_INTERVAL
|
2021-09-09 15:56:47 +00:00
|
|
|
headers['cache-control'] = 'max-age=' + expires
|
2021-09-05 09:58:19 +00:00
|
|
|
|
2021-09-18 03:04:23 +00:00
|
|
|
var len = +headers['content-length']
|
2021-09-05 09:58:19 +00:00
|
|
|
var bin = bytes.subarray(offset, offset + len)
|
2021-09-09 15:56:47 +00:00
|
|
|
|
|
|
|
confObj[path] = new Response(bin, {
|
2021-09-05 09:58:19 +00:00
|
|
|
headers: headers
|
|
|
|
})
|
|
|
|
offset += len
|
|
|
|
}
|
2021-09-09 15:56:47 +00:00
|
|
|
return confObj
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function swEnv() {
|
2021-09-18 03:04:23 +00:00
|
|
|
var jsUrl = location.href.split('?')[0]
|
2021-09-05 09:58:19 +00:00
|
|
|
var rootPath = getRootPath(jsUrl)
|
2021-09-09 15:56:47 +00:00
|
|
|
var isFirst = 1
|
|
|
|
var newJs
|
|
|
|
|
|
|
|
function openFile(path) {
|
|
|
|
return caches.open('.web2img').then(function(cache) {
|
|
|
|
return cache.match(path)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkUpdate() {
|
|
|
|
openFile(rootPath + '.cache-info').then(function(res) {
|
|
|
|
if (!res) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
res.json().then(function(info) {
|
2021-09-10 08:03:06 +00:00
|
|
|
if (Date.now() - info.time < 1000 * UPDATE_INTERVAL) {
|
2021-09-09 15:56:47 +00:00
|
|
|
return
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
2021-09-18 03:04:23 +00:00
|
|
|
var url, opt
|
|
|
|
if ('cache' in Request.prototype) {
|
|
|
|
url = jsUrl
|
|
|
|
opt = {cache: 'no-cache'}
|
|
|
|
} else {
|
|
|
|
url = jsUrl + '?t=' + Date.now()
|
|
|
|
}
|
|
|
|
fetch(url, opt).then(function(res) {
|
2021-09-09 15:56:47 +00:00
|
|
|
res.text().then(function(js) {
|
|
|
|
if (js.indexOf(info.hash) === -1) {
|
2021-09-18 03:04:23 +00:00
|
|
|
newJs = url
|
2021-09-09 15:56:47 +00:00
|
|
|
console.log('[web2img] new version found')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2021-09-05 09:58:19 +00:00
|
|
|
})
|
|
|
|
})
|
2021-09-09 15:56:47 +00:00
|
|
|
}
|
2021-09-10 08:03:06 +00:00
|
|
|
setInterval(checkUpdate, 1000 * UPDATE_INTERVAL)
|
2021-09-05 09:58:19 +00:00
|
|
|
|
2021-09-18 03:04:23 +00:00
|
|
|
function respondFile(url) {
|
|
|
|
var path = new URL(url).pathname
|
|
|
|
.replace(/\/{2,}/g, '/')
|
|
|
|
.replace(/\/$/, '/index.html')
|
|
|
|
|
|
|
|
return openFile(path).then(function(r1) {
|
|
|
|
return r1 || openFile(rootPath + '404.html').then(function(r2) {
|
|
|
|
return r2 || new Response('file not found: ' + path, {
|
|
|
|
status: 404
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function respond(req) {
|
|
|
|
return caches.has('.web2img').then(function(existed) {
|
|
|
|
if (!existed) {
|
|
|
|
// fix cache
|
|
|
|
newJs = jsUrl
|
|
|
|
}
|
|
|
|
if (newJs && req.mode === 'navigate') {
|
|
|
|
var res = new Response('<script src=' + newJs + '></script>', {
|
|
|
|
headers: {
|
|
|
|
'content-type': 'text/html'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
newJs = ''
|
|
|
|
console.log('[web2img] updating')
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
return respondFile(req.url)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-05 09:58:19 +00:00
|
|
|
onfetch = function(e) {
|
2021-09-09 15:56:47 +00:00
|
|
|
if (isFirst) {
|
|
|
|
isFirst = 0
|
|
|
|
checkUpdate()
|
|
|
|
}
|
2021-09-05 09:58:19 +00:00
|
|
|
var req = e.request
|
2021-09-18 03:04:23 +00:00
|
|
|
if (req.url.indexOf(rootPath) === 0 && req.url.indexOf(jsUrl) !== 0) {
|
|
|
|
// url starts with rootPath (exclude x.js)
|
|
|
|
e.respondWith(respond(req))
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-09 15:56:47 +00:00
|
|
|
|
|
|
|
oninstall = function() {
|
|
|
|
skipWaiting()
|
|
|
|
}
|
2021-09-05 09:58:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
}
|