Last active
December 12, 2015 18:38
-
-
Save qqueue/0bd42b745e4eb5b0b7ca to your computer and use it in GitHub Desktop.
streaming comic book zip reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<meta charset=utf-8> | |
<title>zip stream</title> | |
<style> | |
</style> | |
<div id=thumbs></div> | |
<div id=full></div> | |
<script src=pako.js></script> | |
<script src=DataStream.js></script> | |
<script src=zipstream.js></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<meta charset=utf-8> | |
<title>progressive</title> | |
<style> | |
</style> | |
<body> | |
<script src=progressive.js></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
img = document.body.append-child new Image | |
xhr = new XMLHttpRequest | |
..open \GET \052.png | |
..response-type = \moz-blob | |
last = 0 | |
..onprogress = !-> | |
if @response | |
return if (Date.now! - last) < 1000ms | |
last := Date.now! | |
if img.src | |
URL.revokeObjectURL img.src | |
img.src = URL.createObjectURL @response | |
..send! | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
background-color: black; | |
margin: 0; | |
overflow: hidden; | |
} | |
#scrollcontainer { | |
position: absolute; | |
left: 0; | |
top: 0; | |
right: -18px; | |
bottom: 0; | |
overflow-x: hidden; | |
overflow-y: scroll; | |
} | |
#pages { | |
direction: rtl; | |
text-align: center; | |
line-height: 100vh; | |
width: 100vw; | |
} | |
a { | |
display: inline-block; | |
height: 100vh; | |
} | |
.page { | |
max-height:calc(100vh - 1px); | |
max-width: calc(100vw - 1px); | |
margin: 0.5px; | |
vertical-align: middle; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<meta charset=utf-8> | |
<title>reader</title> | |
<link rel=stylesheet href=style.css> | |
<body> | |
<div id=scrollcontainer> | |
<div id=pages></div> | |
<div id=scrollhandle></div> | |
</div> | |
<script src=pako.js></script> | |
<script src=DataStream.js></script> | |
<script src=ui.js></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict" | |
url = location.search.substring 1 # minus '?' | |
get-range = (bytes, cb) !-> | |
xhr = new XMLHttpRequest | |
..open \GET url | |
..response-type = \arraybuffer | |
..set-request-header \Range "bytes=#bytes" | |
..onload = !-> | |
cb new DataStream @response | |
..send! | |
ds <-! get-range \-22 | |
s = ds.readStruct [ | |
\magic \string:4 | |
\diskno \uint16 | |
\centralDirectoryDisk \uint16 | |
\totalEntriesOnDisk \uint16 | |
\totalEntries \uint16 | |
\cdSize \uint32 | |
\cdOffset \uint32 | |
# don't care about comment length or comment | |
# since we're explicitly reading 22 bytes back | |
# it has to be empty anyway | |
] | |
console.log s | |
if not (s.magic is \PK\x05\x06 or s.magic is \PK\x03\x04) | |
throw new Error \invalid! | |
central <-! get-range "#{s.cdOffset}-#{s.cdOffset + s.cdSize}" | |
{headers} = central.readStruct [ | |
\headers [ | |
'[]' | |
[ | |
\sig \string:4 | |
\madeBy \uint16 | |
\versionNeeded \uint16 | |
\bitFlags \uint16 | |
\compression \uint16 | |
\lastModTime \uint16 | |
\lastModDate \uint16 | |
\crc32 \uint32 | |
\compressedSize \uint32 | |
\uncompressedSize \uint32 | |
\filenameLength \uint16 | |
\extraFieldLength \uint16 | |
\fileCommentLength \uint16 | |
\diskNoStart \uint16 | |
\internalAttrs \uint16 | |
\externalAttrs \uint32 | |
\lhOffset \uint32 | |
\filename \string:filenameLength | |
\extraField ['[]' \uint8 \extraFieldLength] | |
\comment ['[]' \uint8 \fileCommentLength] | |
] | |
s.totalEntriesOnDisk | |
] | |
# don't care about signature | |
] | |
console.log headers | |
headers = headers.sort (a,b) -> | |
if a.filename > b.filename | |
1 | |
else if b.filename > a.filename | |
-1 | |
else | |
0 | |
headers = headers.filter -> | |
/\.png$/.test it.filename or /\.jpg$/.test it.filename | |
for header, i in headers | |
header.start = header.lhOffset + 30 + header.filenameLength | |
header.end = header.start + header.compressedSize - 1 | |
header.i = i | |
imgs = [] | |
container = document.get-element-by-id \scrollcontainer | |
just-scrolled = false | |
document.body.add-event-listener \keydown !-> | |
if it.key is \Left or it.key is \ArrowLeft or it.keyIdentifier is \Left | |
container.scrollTop -= window.innerHeight | |
it.preventDefault! | |
else if it.key is \Right or it.key is \ArrowRight or it.keyIdentifier is \Right | |
container.scrollTop += window.innerHeight | |
it.preventDefault! | |
else if it.key is \Enter or it.keyIdentifier is \Enter | |
document.documentElement.mozRequestFullScreen?! | |
document.documentElement.webkitRequestFullscreen?(Element.ALLOW_KEYBOARD_INPUT) | |
todo = new Set headers | |
pages = document.get-element-by-id \pages | |
xhr = new XMLHttpRequest | |
..open \GET url | |
..response-type = \moz-blob | |
..onloadend = !-> document.title = 'reader' | |
..onprogress = !-> | |
document.title = "#{Math.round(it.loaded / it.total * 100)}%" | |
res = @response | |
nu-todo = new Set | |
todo.for-each (header) !-> | |
if res.size > header.end | |
new FileReader | |
..onload = !-> | |
if header.compression is 8 | |
data = pako.inflate-raw new Uint8Array @result | |
else | |
data = new Uint8Array @result | |
type = | |
if /\.png$/.test header.filename | |
\image/png | |
else | |
\image/jpeg | |
blob = new Blob [data], {type} | |
url = URL.createObjectURL blob | |
img = new Image | |
..src = url | |
..title = header.filename | |
..class-name = \page | |
..onclick = !-> | |
{bottom, top} = this.get-bounding-client-rect! | |
console.log top, bottom | |
i = header.i | |
imgs[i] = img | |
a = document.create-element \a | |
..name = i | |
..href = "\##i" | |
a.append-child img | |
# assume we get them in order (pretty safe) | |
pages.append-child a | |
..read-as-array-buffer res.slice header.start, header.end + 1 | |
else | |
nu-todo.add header | |
todo := nu-todo | |
..send! | |
in-zone = false | |
container | |
..add-event-listener \mousemove !-> | |
if window.innerWidth - it.clientX < 100 | |
if not in-zone | |
container.style.right = \0 | |
in-zone := true | |
else | |
if in-zone | |
container.style.right = \-18px | |
in-zone := false | |
var timeout | |
container.add-event-listener \scroll !-> | |
if just-scrolled | |
just-scrolled := false | |
return | |
container.style.right = \0 | |
clearTimeout timeout | |
timeout := setTimeout do | |
!-> | |
if not in-zone | |
container.style.right = \-18px | |
1000 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict" | |
#url = \http://localhost:8888 | |
url = location.hash.substring 1 | |
get-range = (bytes, cb) !-> | |
xhr = new XMLHttpRequest | |
..open \GET url | |
..response-type = \arraybuffer | |
..set-request-header \Range "bytes=#bytes" | |
..onload = !-> | |
cb new DataStream @response | |
..send! | |
# prefetch test | |
fetch = (url, cb) !-> | |
console.log \fetching | |
xhr = new XMLHttpRequest | |
..open \GET url | |
..response-type = \arraybuffer | |
..onloadend = !-> | |
console.log \fetched... | |
cb! | |
..send! | |
console.log \fetched? | |
#<-! fetch url | |
console.log \loaded? | |
ds <-! get-range \-22 | |
s = ds.readStruct [ | |
\magic \string:4 | |
\diskno \uint16 | |
\centralDirectoryDisk \uint16 | |
\totalEntriesOnDisk \uint16 | |
\totalEntries \uint16 | |
\cdSize \uint32 | |
\cdOffset \uint32 | |
# don't care about comment length or comment | |
# since we're explicitly reading 22 bytes back | |
# it has to be empty anyway | |
] | |
if s.magic is not \PK\x05\x06 | |
throw new Error \invalid! | |
console.log s | |
central <-! get-range "#{s.cdOffset}-#{s.cdOffset + s.cdSize}" | |
{headers} = central.readStruct [ | |
\headers [ | |
'[]' | |
[ | |
\sig \string:4 | |
\madeBy \uint16 | |
\versionNeeded \uint16 | |
\bitFlags \uint16 | |
\compression \uint16 | |
\lastModTime \uint16 | |
\lastModDate \uint16 | |
\crc32 \uint32 | |
\compressedSize \uint32 | |
\uncompressedSize \uint32 | |
\filenameLength \uint16 | |
\extraFieldLength \uint16 | |
\fileCommentLength \uint16 | |
\diskNoStart \uint16 | |
\internalAttrs \uint16 | |
\externalAttrs \uint32 | |
\lhOffset \uint32 | |
\filename \string:filenameLength | |
\extraField ['[]' \uint8 \extraFieldLength] | |
\comment ['[]' \uint8 \fileCommentLength] | |
] | |
s.totalEntriesOnDisk | |
] | |
# don't care about signature | |
] | |
thumbs = document.get-element-by-id \thumbs | |
full = document.get-element-by-id \full | |
headers = headers.sort (a,b) -> | |
if a.filename > b.filename | |
1 | |
else if b.filename > a.filename | |
-1 | |
else | |
0 | |
queue = [] | |
overall = document.body.append-child document.create-element \progress | |
for let header in headers | |
console.log header | |
start = header.lhOffset + 30 + header.filenameLength | |
end = start + header.compressedSize - 1 | |
fimg = full.append-child document.create-element \img | |
span = thumbs.append-child document.create-element \span | |
progress = span.append-child document.create-element \progress | |
xhr = new XMLHttpRequest | |
..open \GET url | |
..response-type = \arraybuffer | |
..set-request-header \Range "bytes=#start-#end" | |
..onload = !-> | |
if header.compression is 8 | |
data = pako.inflate-raw new Uint8Array @response | |
else | |
data = new Uint8Array @response | |
type = | |
if /\.png$/.test header.filename | |
\image/png | |
else | |
\image/jpeg | |
console.log type | |
blob = new Blob [data], {type} | |
url = URL.createObjectURL blob | |
timg = new Image | |
..style.max-width = \50px | |
..src = url | |
fimg | |
..style.max-width = \100% | |
..src = url | |
span.append-child timg | |
span.remove-child progress | |
..onprogress = !-> | |
if it.length-computable | |
progress.value = it.loaded / it.total | |
overall.value = it.loaded / it.total | |
..onloadend = !-> | |
if queue.shift! | |
that.send! | |
else | |
document.body.remove-child overall | |
queue.push xhr | |
queue.shift!send! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
file = document.get-element-by-id \file | |
f = new FileReader | |
..onload = !-> | |
js = new JSZip it.target.result | |
console.log js | |
f.readAsArrayBuffer file.files.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment